PostgreSQL error 42601
syntax error at or near
PostgreSQL couldn’t parse the statement, and the quoted word is where it gave up. The mistake is usually just before that point: a reserved word used as a name, a missing or extra comma, MySQL-only syntax, or a quote or bracket that isn’t closed.
ERROR: syntax error at or near "user"
Tested on PostgreSQL 18.6 (also 14–17) · Updated 9 October 2026
What it means
The parser read your statement word by word and reached one that can’t come next. That word is in
the message, and the caret under LINE 1 points at it:
ERROR: syntax error at or near "email"
LINE 1: SELECT id name email FROM customers;
^
The real mistake is often a word or two before the caret. Here the commas are missing:
PostgreSQL read id name as “id, renamed to name”, so email was the first word that made no
sense. syntax error at end of input means the statement stopped early: a clause or bracket
was left unfinished.
Nothing ran; a syntax error is caught before the statement starts.
Common causes
- A reserved word used as a name.
user,order,group,limit,desc,tableand others can’t be table or column names unless you quote them. - A missing comma between columns, so two names run together.
- A trailing comma before
FROM,WHEREor a closing bracket, often after deleting the last column of a list. - MySQL syntax: backticks around names,
AUTO_INCREMENT,LIMIT 10, 20,ON DUPLICATE KEY UPDATE. - An unbalanced quote or bracket:
'O'Brien',count(*. - Clauses in the wrong order:
ORDER BYbeforeWHERE,LIMITbeforeORDER BY. - Generated SQL with a hole in it: an empty
IN ()list,WHEREwith nothing after it, a danglingAND, or a table name passed as a$1parameter.
How to fix it
Quote reserved words, or rename
CREATE TABLE "user" (id int PRIMARY KEY, name text);
SELECT id, "desc" FROM products;
Once a name needs quotes, it needs them everywhere, so renaming (app_user, orders, description)
is usually less trouble. Watch out for user in particular: SELECT * FROM user doesn’t fail. It
returns the name of the current role, because user is a built-in that means current_user; the
table is "user".
Check the commas
Every item in a select list, column list or VALUES list is separated by a comma, and the last one
has none:
SELECT id, name, email FROM customers;
CREATE TABLE notes (id int PRIMARY KEY, body text);
UPDATE customers SET name = 'x' WHERE id = 1;
Translate MySQL syntax
| MySQL | PostgreSQL |
|---|---|
`name` | "name" (or no quotes) |
id int AUTO_INCREMENT PRIMARY KEY | id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY |
LIMIT 10, 20 | LIMIT 20 OFFSET 10 |
ON DUPLICATE KEY UPDATE name = 'Ada' | ON CONFLICT (id) DO UPDATE SET name = 'Ada' |
"text" for a string | 'text' |
PostgreSQL recognises LIMIT 10, 20 and says so with a hint. Double-quoted strings aren’t a syntax
error but a different one: column does not exist. For
upserts, see duplicate key value.
Close quotes and brackets
Inside a string, write an apostrophe twice, or use dollar quoting:
SELECT * FROM customers WHERE name = 'O''Brien';
SELECT * FROM customers WHERE name = $$O'Brien$$;
In application code, pass values as parameters instead of building the string; then quotes inside
values can’t break the SQL. In psql, an unclosed quote or bracket makes it wait for more input
instead of running anything: the prompt changes from app=> to app'> or app(>.
Put clauses in order
SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY … LIMIT … OFFSET.
Guard generated SQL
Parameters can carry values, never table or column names; $1 in place of a name is a syntax error.
For a list that may be empty, use = ANY($1) with an array parameter: an empty array matches nothing,
where IN () doesn’t parse.
Reproduce it
On PostgreSQL 18.6:
CREATE TABLE user (id int PRIMARY KEY, name text);
ERROR: syntax error at or near "user"
LINE 1: CREATE TABLE user (id int PRIMARY KEY, name text);
^
CREATE TABLE "user" (…) works, and then SELECT * FROM user; returns one row, inlet, the current
role. Commas:
ERROR: syntax error at or near "FROM"
LINE 1: SELECT id, name, FROM customers;
^
ERROR: syntax error at or near ")"
LINE 1: CREATE TABLE notes (id int PRIMARY KEY, body text,);
^
MySQL syntax. A backtick is an operator character in PostgreSQL, so the parser only gives up at the next word:
ERROR: syntax error at or near "FROM"
LINE 1: SELECT `name` FROM customers;
^
ERROR: syntax error at or near "AUTO_INCREMENT"
LINE 1: CREATE TABLE things (id int AUTO_INCREMENT PRIMARY KEY);
^
ERROR: LIMIT #,# syntax is not supported
LINE 1: SELECT * FROM customers LIMIT 10, 20;
^
HINT: Use separate LIMIT and OFFSET clauses.
ERROR: syntax error at or near "DUPLICATE"
LINE 1: ...RT INTO customers (id, name) VALUES (1, 'Ada') ON DUPLICATE ...
^
Quotes, brackets and generated SQL:
ERROR: syntax error at or near "Brien"
LINE 1: SELECT * FROM customers WHERE name = 'O'Brien';
^
ERROR: syntax error at end of input
LINE 1: SELECT count(*
^
ERROR: unterminated quoted string at or near "'abc"
LINE 1: SELECT 'abc
^
ERROR: syntax error at or near ")"
LINE 1: SELECT * FROM customers WHERE id IN ();
^
ERROR: syntax error at or near "$1"
LINE 1: PREPARE p(text) AS SELECT * FROM $1;
^
PostgreSQL 14, 15, 16 and 17 print the same messages at the same positions.
In Inlet
Inlet shows the error at the position the server reports, with a hint for common ones, and ⌘↩ runs only the statement under the cursor, so you can check one statement at a time. With your own Anthropic API key, Ask Claude (⌘L) can fix the failed statement; it sends the schema, the SQL and the error, never rows.