ERROR 2014: Commands out of sync; you can't run this command now is raised when a client attempts to send a new command over a MySQL connection while a previous result set has not been fully read or freed. The error symbol is CR_COMMANDS_OUT_OF_SYNC. This is a client-side error (HY000) originating in the MySQL C client library, not on the server.
Impact
This error causes the new command to fail immediately — no rows are affected, no query is executed, and the connection remains blocked until the pending result set is consumed or freed. The error is especially common in applications that use unbuffered queries (streaming results row-by-row rather than fetching the entire result set at once) and then attempt to run a second query on the same connection handle before the first result is exhausted.
In web frameworks and ORMs, this often appears as an unexpected exception mid-request, particularly when lazy-loading related records inside a loop that is itself driven by an open database cursor. PHP's mysqli extension, Python's mysql-connector-python in streaming mode, and direct use of the C API with mysql_use_result() are the most frequent environments where developers encounter this error.
Common Causes
Unbuffered query not fully consumed. Using
mysql_use_result()(C API),mysqli_use_result()(PHP), orMySQLdb.SSCursor/mysql.connectorwithbuffered=False(Python) streams rows one at a time. If you issue a second query on the same connection before fetching all rows and calling the appropriate free function, error 2014 is raised.Iterating over a result set and querying inside the loop. Opening a cursor or result set and then running additional queries (INSERTs, SELECTs, stored procedure calls) on the same connection object inside the iteration loop is a classic trigger. Each inner query tries to use the connection while it is still serving the outer result.
Stored procedure with multiple result sets not fully read. A
CALLto a stored procedure that produces multiple result sets leaves the connection in a multi-result state. Any subsequent command issued before all result sets are consumed andmysql_next_result()(or the driver equivalent) is called will raise 2014.Exception or early return leaving a result set open. An unhandled exception, a
breakout of a fetch loop, or an earlyreturnin a function can leave a result set partially read. Subsequent use of the same connection — often via a connection pool — then fails.Multi-statement queries (
CLIENT_MULTI_STATEMENTS) not fully drained. When theCLIENT_MULTI_STATEMENTSflag is set and you send several semicolon-separated statements, all result sets must be read before the connection can be reused.
Troubleshooting and Resolution Steps
Switch to buffered queries. The simplest fix is to let the driver fetch the entire result set into memory before you proceed. This eliminates the streaming state entirely.
# Python mysql-connector-python — use buffered cursor cursor = conn.cursor(buffered=True) cursor.execute("SELECT id, name FROM orders") for row in cursor: cursor2 = conn.cursor() # safe: outer cursor is buffered cursor2.execute("SELECT * FROM order_items WHERE order_id = %s", (row[0],))// PHP: use mysqli_store_result() instead of mysqli_use_result() $result = $mysqli->query("SELECT id FROM orders"); // buffered by default while ($row = $result->fetch_assoc()) { $mysqli->query("UPDATE orders SET processed=1 WHERE id=" . $row['id']); }Free the result set before issuing the next command. If you must use unbuffered queries, read all rows and then explicitly free the result.
/* C API */ MYSQL_RES *res = mysql_use_result(conn); while ((row = mysql_fetch_row(res))) { /* consume all rows */ } mysql_free_result(res); /* now safe to issue another command */$result = $mysqli->query("SELECT id FROM big_table", MYSQLI_USE_RESULT); while ($row = $result->fetch_assoc()) { /* process */ } $result->free();Use a separate connection for nested queries. When the query pattern genuinely requires issuing queries inside a result-set loop, open a second connection (or borrow a second connection from the pool) for the inner queries.
Drain all result sets from stored procedures.
$mysqli->query("CALL multi_result_proc()"); do { if ($result = $mysqli->store_result()) { $result->free(); } } while ($mysqli->next_result());Check connection pool health. If this error appears intermittently on pooled connections, add logic to discard connections that have an unconsumed result set rather than returning them to the pool. Most connection pool libraries expose a validation hook for this purpose.
Additional Information
- Error 2014 has no SQLSTATE subclass beyond
HY000(general error) because it is a protocol-level client error defined inerrmsg.h, not a server-side SQL condition. - The error is unrelated to query syntax or data — it is purely a connection-state protocol violation.
- In Python's
mysql-connector-python, passingconsume_results=Trueto the connection constructor will automatically discard unread result sets before executing new commands, which can mask the root cause but prevents hard failures. - PyMySQL and
mysqlclient(MySQLdb) buffer results by default, so error 2014 is less common with those drivers unless a low-level cursor type is explicitly selected. - The Go
database/sqldriver (go-sql-driver/mysql) buffers by default and handles multi-results internally, making this error rare in Go applications.
Frequently Asked Questions
Why does this error only appear in production and not locally? Production environments often use connection pooling and higher concurrency. A connection returned to the pool with an unread result set will fail the next caller. Local single-user testing rarely hits the same timing and reuse patterns.
Can I fix this by reconnecting? Reconnecting creates a clean connection and clears the error, but it is expensive and hides the real problem. The correct fix is to ensure result sets are always fully consumed or freed before reusing a connection.
Does this error affect transactions?
Yes. If the error is raised inside an open transaction, the transaction is not automatically rolled back by the error itself, but any subsequent COMMIT or ROLLBACK will also fail until the pending result set is freed, effectively stalling the transaction.
Is error 2014 the same as "Lost connection to MySQL server"?
No. Error 2013 (CR_SERVER_LOST) means the connection dropped. Error 2014 means the connection is still alive but in an unusable state because a result set was not drained. The connection can be recovered by freeing the pending result rather than reconnecting.