go-sql-driver/mysql · error
invalid connection
Error message
invalid connection
What it means
ErrInvalidConn is the catch-all sentinel returned when the underlying connection is no longer usable. readPacket (packets.go:59,101) returns it after any I/O read failure, mc.error() (connection.go:202) returns it for a closed connection, and mysqlTx.Commit/Rollback (transaction.go:17,33,38) return it when the conn is already nil/closed. Unlike driver.ErrBadConn, this value surfaces all the way to the caller, so database/sql will NOT transparently retry it.
Solutions
- Treat ErrInvalidConn as fatal for that transaction/connection: discard both and retry the whole unit of work on a fresh connection from the pool.
- Enable connection liveness checks (CheckConnLiveness=true, the default) and set ConnMaxLifetime shorter than the server's wait_timeout so stale conns are reaped before use.
- Avoid reusing a *sql.Tx or *sql.Conn after any error; immediately discard it.
- Increase server wait_timeout / set TCP keepalives so idle connections are not dropped.
Example fix
// before: reuse tx after error, then Commit fails with ErrInvalidConn
tx, _ := db.Begin()
if _, err := tx.Exec(...); err != nil {
log.Print(err) // tx is now invalid
}
tx.Commit() // -> ErrInvalidConn
// after: roll back and abandon tx on any error
tx, _ := db.Begin()
if _, err := tx.Exec(...); err != nil {
tx.Rollback()
return err
}
return tx.Commit() Defensive patterns
Strategy: retry
Validate before calling
// Before starting a unit of work, confirm the pool is reachable.
if err := db.PingContext(ctx); err != nil {
return fmt.Errorf("db unreachable: %w", err)
} Type guard
func isInvalidConn(err error) bool {
return errors.Is(err, mysql.ErrInvalidConn)
} Try / catch
err := tx.Commit()
if errors.Is(err, mysql.ErrInvalidConn) {
// conn is dead and the op did not complete; the whole tx must be
// retried on a fresh connection. Do NOT reuse tx or the conn.
return retryWholeUnit()
} Prevention
- Set db.SetConnMaxLifetime() below the server's wait_timeout so dead conns are reaped first.
- Keep CheckConnLiveness=true (default) so the pool checks conns before handing them out.
- Never reuse a *sql.Tx or *sql.Conn after any error from it.
- Always pair Begin() with a Commit() or Rollback(); defer a Rollback() right after Begin().
When it happens
Trigger: Returned by tx.Commit()/tx.Rollback() when the transaction's connection was already closed or committed once; by any query/exec/ping when a network read fails mid-exchange (server killed, TCP reset, ReadTimeout elapsed); by mc.error() when an operation runs against a connection whose closed flag is set.
Common situations: Calling tx.Commit() twice or using a tx after the connection died; idle pooled connections killed by the server's wait_timeout; network blips; a previous statement that desynced the connection and forced a close.
Related errors
AI-assisted analysis of go-sql-driver/mysql@03d76c7e07 (2026-08-07).
Data as JSON: /api/errors/971c60aee1b56f67.
Report an issue: GitHub.
Appendix: source
Thrown at errors.go:20
//
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
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")
)View on GitHub (pinned to 03d76c7e07)