go-sql-driver/mysql · error
commands out of sync. You can't run this command now
Error message
commands out of sync. You can't run this command now
What it means
ErrPktSync is returned from readPacket (packets.go:115) when a regular packet's sequence number does not match the expected value and the payload is not an error packet. Sequence numbers track request/response pairing, so a mismatch means the connection's command stream has been corrupted — typically by concurrent use of one connection or by issuing a new command before draining the previous result set.
Solutions
- Always fully consume or Close() a *sql.Rows before issuing any other command on the same connection.
- Do not share a single *sql.Conn between goroutines; use *sql.DB (which pools) or serialize access with a mutex.
- If you need exclusive use, use db.Conn(ctx) and release it only after the result set is drained.
- Treat the connection as poisoned after this error and let the pool discard it.
Example fix
// before: start a new query while rows still open on same conn
rows, _ := db.Query("SELECT ...")
db.Exec("UPDATE ...") // rows not drained -> ErrPktSync
rows.Close()
// after: drain (or close) rows first
rows, _ := db.Query("SELECT ...")
for rows.Next() { /* ... */ }
rows.Close() // connection returned cleanly
db.Exec("UPDATE ...") Defensive patterns
Strategy: validation
Validate before calling
// Enforce a single-writer-per-conn invariant in your data layer.
type lockedConn struct {
conn *sql.Conn
mu sync.Mutex
}
func (lc *lockedConn) exec(ctx context.Context, q string, args ...any) error {
lc.mu.Lock()
defer lc.mu.Unlock()
_, err := lc.conn.ExecContext(ctx, q, args...)
return err
} Type guard
func isPktSync(err error) bool {
return errors.Is(err, mysql.ErrPktSync)
} Try / catch
if errors.Is(err, mysql.ErrPktSync) {
// connection stream is desynced and poisoned: abandon this conn,
// fix the concurrent/un-drained access pattern, then retry.
} Prevention
- Always Close() or fully iterate *sql.Rows before the next statement.
- Never share a single *sql.Conn across goroutines; use *sql.DB for concurrency.
- Defer rows.Close() immediately after Query.
- After any packet-sync error, discard the connection rather than reusing it.
When it happens
Trigger: Using a single *sql.Conn / raw connection from multiple goroutines without serialization; calling Query and starting another Exec before fully iterating the returned *sql.Rows; interleaving a ping with an in-flight result read on a shared connection.
Common situations: Sharing a *sql.Conn across goroutines (the *sql.DB pool is safe, a single Conn is not); forgetting rows.Close()/rows.Next() exhaustion before the next statement; driver-level misuse wrapped behind a custom connection manager.
Related errors
- commands out of sync. Did you run multiple statements at…
- busy buffer
- invalid compressed packet: uncompressed length in header is
- MySQL server does not support required protocol 41+
- protocol error, illegal decimals value
AI-assisted analysis of go-sql-driver/mysql@03d76c7e07 (2026-08-07).
Data as JSON: /api/errors/7e964416937ec691.
Report an issue: GitHub.
Appendix: source
Thrown at errors.go:27
package mysql
import (
"errors"
"fmt"
"log"
"os"
)
// Various errors the driver might return. Can change between driver versions.
var (
ErrInvalidConn = errors.New("invalid connection")
ErrMalformPkt = errors.New("malformed packet")
ErrNoTLS = errors.New("TLS requested but server does not support TLS")
ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN")
ErrNativePassword = errors.New("this user requires mysql native password authentication")
ErrOldPassword = errors.New("this user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords")
ErrUnknownPlugin = errors.New("this authentication plugin is not supported")
ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+")
ErrPktSync = errors.New("commands out of sync. You can't run this command now")
ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?")
ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the `Config.MaxAllowedPacket`")
ErrBusyBuffer = errors.New("busy buffer")
// errBadConnNoWrite is used for connection errors where nothing was sent to the database yet.
// If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn
// to trigger a resend. Use mc.markBadConn(err) to do this.
// See https://github.com/go-sql-driver/mysql/pull/302
errBadConnNoWrite = errors.New("bad connection")
)
var defaultLogger = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime))
// Logger is used to log critical error messages.
type Logger interface {
Print(v ...any)
}View on GitHub (pinned to 03d76c7e07)