How the Go MySQL Driver Detects Stale Connections in the Connection Pool

The go-sql-driver/mysql detects stale or dead connections by implementing the driver.SessionResetter and driver.Validator interfaces, using a non-blocking socket probe in ResetSession to verify liveness before reuse, and returning driver.ErrBadConn to signal the pool to discard unusable connections.

The go-sql-driver/mysql package leverages Go’s standard database/sql connection pool for connection management, but it supplies critical lifecycle hooks that enable proactive detection of broken TCP sockets. By understanding how the driver validates connection health before handing connections back to your application, you can configure resilient database clients that automatically survive network interruptions and MySQL server timeouts.

The ResetSession Hook and Liveness Probing

When the database/sql pool retrieves a cached connection for reuse, it invokes the driver’s ResetSession method, which implements the driver.SessionResetter interface. In connection.go (lines 96–119), this method checks the CheckConnLiveness configuration flag before allowing the connection to proceed.

If CheckConnLiveness is true (the default), the driver executes a liveness probe via the connCheck function. This function performs a non-blocking read operation on the underlying network socket to determine if the connection is still viable. The probe operates exclusively on Linux and Darwin systems, where it can interact directly with socket file descriptors.

Low-Level Socket Verification in connCheck

The connCheck implementation in conncheck.go (lines 23–55) attempts a zero-byte read with MSG_PEEK to check the socket state without consuming data. The logic interprets the system call result as follows:

  • EOF returned: The socket is dead; the connection has been closed by the server or network.
  • EAGAIN or EWOULDBLOCK returned: The socket is alive but has no data available, which is the expected state for an idle connection.
  • Any other error: Treated as a failure indicating the connection is unusable.

When connCheck detects a dead socket, ResetSession returns driver.ErrBadConn. The database/sql pool interprets this error as a signal to discard the cached connection and establish a fresh one, ensuring your application never receives a broken socket.

The IsValid Validator Hook

Beyond the session reset hook, the driver also implements the driver.Validator interface via the IsValid method in connection.go (lines 124–128). The pool may call this method to quickly verify connection state without performing a full network probe.

The IsValid implementation checks two conditions:

  • Whether the connection has been explicitly closed.
  • Whether the buffer is currently marked as busy via buf.busy().

If either condition is true, the method returns false, prompting the pool to remove the connection from the cache immediately.

Configuration and Error Handling

The liveness check behavior is controlled by the checkConnLiveness DSN parameter, defined in dsn.go (lines 62–68). The NewConfig function in dsn.go (lines 96–98) sets this flag to true by default, meaning stale connection detection is active unless explicitly disabled.

When the driver encounters any error during the liveness verification, it wraps the error as driver.ErrBadConn. This standardized error type allows the database/sql pool to distinguish between transient query failures (which might be retried on the same connection) and fundamental connection corruption (which requires eviction and replacement).

Practical Implementation Examples

Example 1: Default Stale Connection Detection

By default, the driver enables liveness checks without requiring explicit configuration. The pool automatically verifies connections on reuse.

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    // DSN without explicit checkConnLiveness uses the default (true)
    dsn := "user:pass@tcp(127.0.0.1:3306)/dbname"
    db, _ := sql.Open("mysql", dsn)

    // The pool invokes ResetSession on each reused connection.
    // Dead sockets trigger driver.ErrBadConn, causing automatic replacement.
}

Example 2: Disabling Liveness Checks

You can disable the probe by setting checkConnLiveness=false in the DSN. This eliminates the overhead of the socket read but risks handing stale connections to your application.

dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?checkConnLiveness=false"
db, _ := sql.Open("mysql", dsn)

// The pool skips the connCheck probe. Use only in reliable network
// environments where you want to avoid the extra read-deadline overhead.

Example 3: Pool Sizing with Stale Connection Handling

Configure pool limits to work in concert with the driver’s detection mechanisms. Dead idle connections are purged when detected during reuse, so you can allow indefinite connection lifetimes while maintaining reliability.

db.SetMaxIdleConns(10)      // Maintain up to 10 idle connections
db.SetMaxOpenConns(50)      // Maximum total connections
db.SetConnMaxLifetime(0)    // Connections live indefinitely unless flagged bad

Summary

  • ResetSession hook: Called by the pool before reuse; triggers the liveness probe in connection.go.
  • connCheck probe: Performs non-blocking socket reads in conncheck.go to detect EOF or errors on Linux/Darwin.
  • IsValid validator: Provides fast state checks via connection.go to detect closed or busy connections.
  • Error signaling: Returns driver.ErrBadConn to force pool eviction of dead connections.
  • Configurable behavior: Controlled by checkConnLiveness DSN flag (default true) defined in dsn.go.

Frequently Asked Questions

How does the MySQL driver determine if a connection is stale?

The driver uses the connCheck function in conncheck.go to perform a non-blocking read on the socket file descriptor. If the read returns EOF, the connection is dead. If it returns EAGAIN or EWOULDBLOCK, the socket is alive. This check runs inside the ResetSession method (implemented in connection.go) whenever the pool prepares to reuse a connection.

What happens when the driver detects a dead connection?

When connCheck detects a dead socket or IsValid finds the connection closed, the driver returns driver.ErrBadConn. The database/sql pool recognizes this error, discards the connection from the cache, and creates a new connection for the operation. This process is transparent to the application, which receives a fresh connection without explicit retry logic.

Can I disable the automatic stale connection detection?

Yes. Set the DSN parameter checkConnLiveness=false to skip the connCheck probe. This reduces overhead but increases the risk of your application receiving a broken connection from the pool. Disable this only when operating in highly reliable network environments where socket deaths are extremely rare.

Does the liveness check work on all operating systems?

No. The connCheck implementation relies on platform-specific socket operations and is only available on Linux and Darwin (macOS). On other operating systems, the driver falls back to the IsValid validator and relies on write errors during query execution to detect stale connections, though the ResetSession logic will still run if CheckConnLiveness is enabled.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →