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

  1. Always fully consume or Close() a *sql.Rows before issuing any other command on the same connection.
  2. Do not share a single *sql.Conn between goroutines; use *sql.DB (which pools) or serialize access with a mutex.
  3. If you need exclusive use, use db.Conn(ctx) and release it only after the result set is drained.
  4. 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

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


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)