Skip to content
MySQL Error 1064: You Have an Error in SQL Syntax

Click to use (opens in a new tab)

MySQL Error 1064: You Have an Error in SQL Syntax

September 27, 2026 by Chat2DBChat2DB Team

ERROR 1064 (42000): You have an error in your SQL syntax is the MySQL parser telling you it could not turn your text into a valid statement. Nothing was executed, no rows were touched, and no permission or data check happened yet. The problem is purely the shape of the SQL.

The message looks unhelpful at first, but it contains a precise pointer if you know how to read it. This guide explains that pointer, then walks through the causes that produce almost every 1064 in practice on MySQL 8.0 and 8.4, each with a broken statement, the exact error it produces, and the fixed version. Notes on MariaDB are included where its behavior differs.

All error output below was produced on a MySQL 8.0 server; 8.4 LTS behaves the same for these cases.

How to Read the Error Message

Here is a typical 1064:

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near
'rank FROM scores' at line 1

It has three useful parts:

  • 1064 is the error number, and 42000 is the SQLSTATE class for syntax errors and access rule violations.
  • near '...' shows the remaining text of the statement starting at the token where the parser gave up.
  • at line N is the line number inside the statement (not inside your script file) where that token is.

The "near" Text Starts Where the Parser Stopped

The most important habit: the quoted text is not "the part that is wrong". It is everything from the first token the parser could not accept to the end of the statement (truncated if long). The actual mistake is usually the token right before the quoted text, or the quoted token itself.

SELECT id, player, FROM scores;
ERROR 1064 (42000): ... for the right syntax to use near 'FROM scores' at line 1

FROM is a perfectly valid keyword. The error is the trailing comma right before it: after a comma, the parser expects another column expression, and FROM is not one. So look at the boundary between what was accepted and what was quoted.

An Empty "near ''" Means the Statement Ended Too Early

When the quoted text is empty, the parser hit the end of the input while it still expected more:

SELECT * FROM scores WHERE id = 1 ORDER BY;
ERROR 1064 (42000): ... for the right syntax to use near '' at line 1

Typical causes are a dangling ORDER BY, WHERE, or AND, an unclosed parenthesis, or a stored procedure body cut off at its first semicolon (covered below under DELIMITER).

Line Numbers Are Relative to the Statement

When you run a script file with the mysql client, you get two line numbers:

SELECT id,
       player,
       score,
FROM scores
WHERE id = 1;
ERROR 1064 (42000) at line 8: You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right syntax to use near
'FROM scores
WHERE id = 1' at line 4

at line 8 (after the error code) is the line in the script file where this statement began. at line 4 (at the end) is the line within the statement. Line 4 of the statement is FROM scores, and the stray comma is at the end of line 3. Format long queries one clause per line and the line number becomes a very accurate pointer.

Cause 1: Reserved Words Used as Identifiers

This is the most common 1064 after an upgrade from MySQL 5.7 to 8.0. MySQL 8.0 added window functions and other features, and several words became reserved. Among them: RANK, DENSE_RANK, ROW_NUMBER, LEAD, LAG, GROUPS, WINDOW, OVER, ROWS, CUME_DIST, NTILE, RECURSIVE, LATERAL, SYSTEM, and OF. Older reserved words such as ORDER, GROUP, KEY, DESC, and INDEX catch people too.

Each of the following fails on 8.0:

SELECT id, score, RANK() OVER (ORDER BY score DESC) AS rank FROM scores;
CREATE TABLE groups (id INT PRIMARY KEY);
CREATE TABLE lead (id INT PRIMARY KEY);
SELECT * FROM order;
ERROR 1064 (42000): ... to use near 'rank FROM scores' at line 1
ERROR 1064 (42000): ... to use near 'groups (id INT PRIMARY KEY)' at line 1
ERROR 1064 (42000): ... to use near 'lead (id INT PRIMARY KEY)' at line 1
ERROR 1064 (42000): ... to use near 'order' at line 1

Notice that in every case the quoted text starts with the reserved word itself, which is a strong hint.

Fix: Quote the Identifier or Rename It

Wrap the identifier in backticks:

SELECT id, score, RANK() OVER (ORDER BY score DESC) AS `rank` FROM scores;
CREATE TABLE `groups` (id INT PRIMARY KEY);
SELECT * FROM `order`;

Qualifying a column with its table name also works, because a word after a dot is always read as an identifier: SELECT s.rank FROM scores s is valid even when rank is a column name.

For long-lived schemas, renaming is better (score_rank, user_groups, orders), since every future query, ORM mapping, and ad hoc report would otherwise need the backticks. You can check a word against the server's own list:

SELECT word, reserved
FROM information_schema.KEYWORDS
WHERE word IN ('RANK', 'GROUPS', 'LEAD', 'WINDOW', 'SYSTEM');

reserved = 1 means it must be quoted when used as an identifier. MariaDB has its own reserved word list, and it differs from MySQL's, so a schema that works on MariaDB can still fail on MySQL 8.0 and vice versa.

Cause 2: Missing or Extra Commas

Commas produce a large share of 1064 errors, and they show up in three places.

A Trailing Comma Before FROM or a Closing Parenthesis

CREATE TABLE t2 (id INT, name VARCHAR(10),);
ERROR 1064 (42000): ... to use near ')' at line 1

Remove the comma after the last column or constraint definition. The same applies to the last item before FROM in a SELECT list, as shown earlier.

A Missing Comma Between Columns

SELECT id player score FROM scores;
ERROR 1064 (42000): ... to use near 'score FROM scores' at line 1

MySQL reads id player as "column id with alias player", which is valid. The third bare word, score, has nowhere to go. Missing commas are dangerous because with only two columns (SELECT id player FROM scores) there is no error at all: you silently get one column named player that contains the ids.

A Missing Comma in SET or VALUES Lists

UPDATE t SET a = 1 b = 2 fails near b = 2, and INSERT ... VALUES (1, 'a') (2, 'b') fails near the second tuple. Both need commas between items.

Cause 3: Wrong Quotes

MySQL uses three kinds of quoting with different meanings:

QuoteMeaningExample
Single quotesString literal'alice'
BackticksIdentifier (table, column, alias)`order`
Double quotesString literal by default; identifier only with ANSI_QUOTES sql_mode"alice"

Single Quotes Around a Table Name

SELECT `id` FROM 'scores';
ERROR 1064 (42000): ... to use near ''scores'' at line 1

'scores' is a string, and a string cannot follow FROM. Use scores or `scores`.

Smart Quotes Pasted From Documents or Chat

Word processors, slide decks, and some chat tools replace ' with typographic quotes (U+2018 and U+2019):

SELECT * FROM scores WHERE player = ‘alice’;
ERROR 1064 (42000): ... to use near '‘alice’' at line 1

The characters look almost identical in many fonts. In some positions the curly quotes are even accepted as part of an unquoted identifier, and you get ERROR 1054 Unknown column instead. Retype the quotes or run a find and replace for ‘ ’ “ ” before executing SQL copied from a document.

Double Quotes and ANSI_QUOTES

With the default sql_mode, WHERE player = "alice" works because double quotes delimit a string. If the server or session has ANSI_QUOTES enabled (common when porting from PostgreSQL), "alice" becomes a column name. Use single quotes for strings everywhere and the question never comes up.

An Unescaped Quote Inside a String

WHERE name = 'O'Brien' ends the string after O and leaves Brien' dangling. Double the quote ('O''Brien') or, far better in application code, use parameterized queries so the driver handles escaping.

Cause 4: MySQL 5.7 Syntax Removed in 8.0

A query that ran for years on 5.7 can start failing right after an upgrade. These are the removals that surface as 1064.

GROUP BY With ASC or DESC

MySQL 5.7 allowed implicit sorting through GROUP BY col DESC. This was removed in 8.0.13:

SELECT player, COUNT(*) FROM scores GROUP BY player DESC;
ERROR 1064 (42000): ... to use near 'DESC' at line 1

Fixed:

SELECT player, COUNT(*) FROM scores GROUP BY player ORDER BY player DESC;

Also note that 8.0 no longer sorts GROUP BY results implicitly, so add ORDER BY whenever the order matters.

SQL_CACHE

The query cache was removed in MySQL 8.0, together with the SQL_CACHE modifier:

SELECT SQL_CACHE * FROM scores;
ERROR 1064 (42000): ... to use near 'FROM scores' at line 1

The parser now treats SQL_CACHE as a column name, reads * as multiplication, and then finds FROM where a second operand should be. Delete the modifier. SQL_NO_CACHE is still accepted in 8.0 but has no effect and raises a deprecation warning. MariaDB still has a query cache, so both modifiers remain valid there.

GRANT ... IDENTIFIED BY and PASSWORD()

Creating a user implicitly with GRANT was removed in 8.0:

GRANT SELECT ON demo.* TO 'app'@'%' IDENTIFIED BY 'secret';
ERROR 1064 (42000): ... to use near 'IDENTIFIED BY 'secret'' at line 1

Split it into two statements:

CREATE USER 'app'@'%' IDENTIFIED BY 'secret';
GRANT SELECT ON demo.* TO 'app'@'%';

Likewise, the PASSWORD() function is gone. SELECT PASSWORD('x'); fails near ('x'). Use ALTER USER ... IDENTIFIED BY to change passwords. If password problems follow the upgrade, see MySQL Error 1045: Access Denied.

Cause 5: Syntax From Another SQL Dialect

SQL copied from SQL Server, PostgreSQL, or Oracle examples is a steady source of 1064. The parser rejects the foreign construct at exactly the point where it appears.

TOP Instead of LIMIT

SELECT TOP 10 * FROM scores;
ERROR 1064 (42000): ... to use near '10 * FROM scores' at line 1

MySQL reads TOP as a column name, then fails on 10. Use SELECT * FROM scores ORDER BY score DESC LIMIT 10;.

PostgreSQL :: Casts and ILIKE

SELECT score::text FROM scores;
SELECT * FROM scores WHERE player ILIKE 'a%';
ERROR 1064 (42000): ... to use near '::text FROM scores' at line 1
ERROR 1064 (42000): ... to use near 'ILIKE 'a%'' at line 1

MySQL equivalents:

SELECT CAST(score AS CHAR) FROM scores;
SELECT * FROM scores WHERE player LIKE 'a%';

With the default _ai_ci collations, LIKE is already case-insensitive, so ILIKE is not needed. For a case-insensitive match on a case-sensitive column, use LOWER(player) LIKE 'a%' or player LIKE 'a%' COLLATE utf8mb4_0900_ai_ci.

RETURNING

INSERT INTO scores VALUES (1, 'a', 1) RETURNING id;
ERROR 1064 (42000): ... to use near 'RETURNING id' at line 1

MySQL has no RETURNING clause. Use LAST_INSERT_ID() after the insert, or your driver's insert id property. MariaDB supports DELETE ... RETURNING and, since 10.5, INSERT ... RETURNING, which is a common reason a query works on MariaDB and fails on MySQL.

LIMIT in a Multi-Table UPDATE Is a Different Error

People often expect this to be a syntax error:

UPDATE scores s
JOIN players p ON p.id = s.id
SET s.score = 0
WHERE p.active = 0
LIMIT 100;

It is not 1064. MySQL parses it and then rejects it with a separate error:

ERROR 1221 (HY000): Incorrect usage of UPDATE and LIMIT

ORDER BY and LIMIT are only allowed in single-table UPDATE and DELETE. To batch a join-based update, select the keys first:

UPDATE scores
SET score = 0
WHERE id IN (
  SELECT id FROM (
    SELECT s.id
    FROM scores s
    JOIN players p ON p.id = s.id
    WHERE p.active = 0
    LIMIT 100
  ) AS batch
);

The extra derived table is needed because MySQL does not allow LIMIT directly inside an IN subquery. Batching like this also keeps locks short; if large updates are timing out, see MySQL Lock Wait Timeout Exceeded.

Cause 6: Stored Programs Without DELIMITER

A procedure, function, or trigger body contains semicolons. The mysql command-line client splits input on ; by default, so it sends the procedure to the server in pieces:

CREATE PROCEDURE add_score(IN p_id INT)
BEGIN
  UPDATE scores SET score = score + 1 WHERE id = p_id;
  SELECT score FROM scores WHERE id = p_id;
END;
ERROR 1064 (42000): ... for the right syntax to use near '' at line 3
ERROR 1054 (42S22): Unknown column 'p_id' in 'where clause'
ERROR 1064 (42000): ... for the right syntax to use near 'END' at line 1

The first chunk ends after the UPDATE line, so the parser sees an unfinished BEGIN block (the empty near ''). The remaining pieces then fail on their own. Change the client delimiter so the whole body is sent as one statement:

DELIMITER $$
 
CREATE PROCEDURE add_score(IN p_id INT)
BEGIN
  UPDATE scores SET score = score + 1 WHERE id = p_id;
  SELECT score FROM scores WHERE id = p_id;
END$$
 
DELIMITER ;

DELIMITER Is Not SQL

DELIMITER is a command of the mysql client (and of some GUI tools), not a server statement. If you send it through a driver, ORM migration, or PREPARE, the server rejects it:

ERROR 1064 (42000): ... to use near 'DELIMITER $$' at line 1

When creating routines from application code, drop the DELIMITER lines entirely and send the CREATE PROCEDURE ... END text as a single statement. The driver sends one statement per call, so the internal semicolons are not a problem.

Cause 7: Features Your Server Version Does Not Have

The phrase "check the manual that corresponds to your MySQL server version" is literal. Syntax from a newer release fails on an older server with 1064. Some examples and the version they require:

SyntaxNeeds
WITH common table expressions, WITH RECURSIVE8.0
Window functions (ROW_NUMBER() OVER (...))8.0
JSON_TABLE()8.0.4
Functional key parts, expression defaults DEFAULT (expr)8.0.13
LATERAL derived tables8.0.14
Enforced CHECK constraints8.0.16
INSERT ... AS new ON DUPLICATE KEY UPDATE col = new.col8.0.19
VALUES ROW(...) table value constructor8.0.19

Always confirm what you are connected to before debugging syntax:

SELECT VERSION();

A value like 5.7.44 explains why a CTE fails, and a value like 10.11.8-MariaDB explains why a MySQL-only feature such as the INSERT ... AS new row alias fails. Managed services and CI containers are frequent surprises here, because they may run an older version than your laptop.

Cause 8: Drivers and ORMs Sending Multiple Statements

Most drivers disable multi-statement execution by default as a protection against SQL injection. If you send two statements in one call, the server parses the whole string as a single statement and fails at the start of the second one:

SELECT * FROM scores WHERE id = 1; SELECT 2;
ERROR 1064 (42000): ... for the right syntax to use near 'SELECT 2' at line 1

The same text runs fine in the mysql client, which splits on ; before sending. That difference ("works in the terminal, fails in my app") is the giveaway.

Fixes, in order of preference:

  1. Send one statement per call. Wrap them in a transaction if they must be atomic.
  2. If you are running a migration file, use the migration tool's own splitter or the mysql client.
  3. Enable multi statements only for trusted, non-user input: multipleStatements: true in Node.js mysql2, allowMultiQueries=true in the Connector/J URL, or the CLIENT.MULTI_STATEMENTS flag in PyMySQL.

A related driver case: a missing semicolon between statements in a script, which produces near 'SELECT 2' at line 2 because the parser read both lines as one statement.

Cause 9: Placeholders and String-Built SQL

When SQL is assembled with string concatenation or templating, the statement that reaches the server may not be the one you think. Common results:

  • An empty variable produces WHERE id = followed by nothing, which fails with near ''.
  • An unescaped value such as O'Brien breaks the quoting.
  • A ? placeholder used for a table or column name fails, because placeholders can only stand in for values.

Log the final SQL string just before execution (most drivers and ORMs have a debug or query log option) and run it by hand. Use bound parameters for values, and a fixed allowlist for any dynamic identifiers.

A Repeatable Debugging Routine

When a 1064 is not obvious, this sequence finds it quickly:

  1. Read the near '...' text and inspect the token immediately before it.
  2. If the quoted text starts with a word, check whether that word is reserved in information_schema.KEYWORDS.
  3. Run SELECT VERSION(); and compare the feature you are using with the version table above.
  4. Reformat the statement with one clause per line and re-run it so at line N narrows the location.
  5. Delete clauses from the end until the statement parses, then add them back one at a time.
  6. If it comes from application code, capture the final SQL the driver sends, not the template.

An editor with MySQL-aware syntax highlighting makes steps 1 and 2 almost instant, because reserved words and unbalanced quotes are colored differently. Chat2DB (opens in a new tab) highlights MySQL 8.0 keywords and lets you run a single statement under the cursor, which is handy when bisecting a long script. To decode other numeric codes that appear alongside 1064 (like 1054 or 1221 above), you can look up any MySQL error number with the free MySQL error code lookup tool (opens in a new tab).

FAQ

Why does my query work in a GUI tool but fail with 1064 in my application?

Usually because the tool splits the script into statements and handles DELIMITER, while your driver sends the whole string as one statement. Send one statement per call, remove DELIMITER lines, or enable multi statements for trusted scripts. Also confirm both are connected to the same server version.

Is error 1064 the same in MySQL and MariaDB?

The number and SQLSTATE are the same, and the message says "MariaDB server version" instead of "MySQL server version". The accepted syntax differs, though: MariaDB supports RETURNING, still accepts SQL_CACHE, and has a different reserved word list, so a statement can fail on one and succeed on the other.

Can I make MySQL 8.0 accept the old 5.7 syntax?

No sql_mode restores removed syntax such as GROUP BY ... DESC, SQL_CACHE, or GRANT ... IDENTIFIED BY. The statements have to be rewritten. Search your codebase for these patterns and for newly reserved words before upgrading, and test the application against an 8.0 or 8.4 instance.

Why does the error point to a line that looks correct?

Because the near text starts at the first token the parser could not accept, and the real mistake is often at the end of the previous line: a trailing comma, a missing comma, or an unclosed quote. Look immediately before the quoted text rather than inside it.