The MySQL client error 2014 occurs when you attempt to execute a new query before properly consuming all results from the previous query. This happens when client functions are called in the wrong order, leaving the client and server out of sync.
Error 2014 (CR_COMMANDS_OUT_OF_SYNC) indicates that the MySQL client and server are out of sync with each other. In MySQL's client-server protocol, you must fetch or consume all results from the previous command before issuing a new one. This error is a client-side protocol violation that occurs when your application tries to send a new command while the previous command's results are still pending. MySQL's protocol is strictly sequential - each command must be fully completed before starting a new one. The error commonly appears when working with stored procedures, unbuffered queries, or when improperly managing result sets in application code.
If you're using stored procedures, iterate through ALL result sets including the final empty one:
// PHP mysqli example
$mysqli->multi_query("CALL my_procedure()");
// Process all result sets
do {
if ($result = $mysqli->store_result()) {
while ($row = $result->fetch_assoc()) {
// Process your rows
}
$result->free();
}
} while ($mysqli->more_results() && $mysqli->next_result());
// Now you can safely execute another query# Python MySQLdb example
cursor.callproc('my_procedure')
# Consume all result sets
for result in cursor.stored_results():
rows = result.fetchall()
# Process rows
# Now safe to execute another queryAlways free result sets when you're done with them:
// C API example
MYSQL_RES *result = mysql_store_result(conn);
if (result) {
// Process result
while ((row = mysql_fetch_row(result))) {
// Handle row
}
mysql_free_result(result); // Critical: free before next query
}
// Now safe to execute another query
mysql_query(conn, "SELECT * FROM users");// Node.js mysql2 example
connection.query('SELECT * FROM table1', (err, results) => {
// Process results
// Results are automatically consumed here
// Now safe to execute another query
connection.query('SELECT * FROM table2', (err, results) => {
// Process second query
});
});mysql_store_result() retrieves the entire result set immediately, making it easier to manage:
// Buffered query - entire result retrieved at once
MYSQL_RES *result = mysql_store_result(conn);
if (result) {
// All rows are now in memory
// Safe to execute other queries even before processing all rows
mysql_free_result(result);
}Note: mysql_use_result() is unbuffered and requires fetching ALL rows before executing another query, which is error-prone.
Enable multi-result support when connecting to handle stored procedures properly:
// PHP - enable CLIENT_MULTI_RESULTS
$mysqli = new mysqli($host, $user, $pass, $db);
$mysqli->options(MYSQLI_OPT_CONNECT_FLAGS, MYSQLI_CLIENT_MULTI_RESULTS);# Python - enable multiStatements in connection string
connection = mysql.connector.connect(
host='localhost',
user='user',
password='password',
database='mydb',
allow_multi_results=True
)// Node.js mysql2 - enable multipleStatements
const connection = mysql.createConnection({
host: 'localhost',
user: 'user',
password: 'password',
database: 'mydb',
multipleStatements: true
});If using connection pools, ensure connections are clean before returning to pool:
// Node.js with connection pool
pool.getConnection((err, connection) => {
connection.query('CALL my_proc()', (err, results) => {
// Process ALL result sets
if (Array.isArray(results)) {
results.forEach(resultSet => {
// Process each result set
});
}
// Release connection only after ALL results consumed
connection.release();
});
});### Understanding MySQL Protocol Sync
The MySQL client-server protocol is strictly sequential. Each command follows this lifecycle:
1. Client sends command
2. Server processes and sends result packets
3. Client must read ALL result packets
4. Server sends final OK/ERROR packet
5. Only then can the client send a new command
Breaking this sequence causes the "commands out of sync" error.
### Stored Procedures and Result Sets
Stored procedures can return multiple result sets, and MySQL ALWAYS appends a final empty result set containing procedure execution metadata. Many client libraries don't automatically consume this final result set, requiring explicit handling with next_result() or equivalent.
### Debugging Tips
Enable MySQL general query log to see the exact sequence of commands:
SET GLOBAL general_log = 1;
SET GLOBAL log_output = 'TABLE';
SELECT * FROM mysql.general_log ORDER BY event_time DESC LIMIT 20;This shows which query is executing when the sync error occurs.
### Client Library Differences
Different MySQL client libraries handle result buffering differently:
- MySQLi/PDO (PHP): Requires explicit next_result() loops for procedures
- mysql.connector (Python): Use stored_results() iterator
- mysql2 (Node.js): Auto-consumes single result sets but requires care with procedures
- Go sql driver: Use query.Scan() to consume all rows or Close() to discard
### Persistent Connections Caveat
With persistent connections, if the MySQL server restarts while connections are open, they may remain in CLOSE_WAIT state on the client side. Set connection lifetime shorter than wait_timeout (default 28800 seconds) to avoid this.
ERROR 1064: You have an error in your SQL syntax
How to fix "ERROR 1064: You have an error in your SQL syntax" in MySQL
ERROR 1054: Unknown column in field list
Unknown column in field list
ER_WINDOW_RANGE_FRAME_NUMERIC_TYPE (3589): RANGE frame requires numeric ORDER BY expression
RANGE frame requires numeric ORDER BY expression in MySQL window functions
CR_ALREADY_CONNECTED (2058): Handle already connected
How to fix "CR_ALREADY_CONNECTED (2058): Handle already connected" in MySQL
ER_WINDOW_DUPLICATE_NAME (3591): Duplicate window name
How to fix ER_WINDOW_DUPLICATE_NAME (3591) in MySQL window functions