Two different problems wear this one error: queries dying mid-flight (packet/timeout limits) and idle pools dying (server closes them first). Which one you have changes the fix entirely.
MySQL closes idle connections after wait_timeout (default 8h, often tuned lower). Your pool doesn't know they're dead until the next query fails.
Large INSERT or BLOB sends hit the packet limit and the server drops the connection mid-query.
A load balancer between app and DB (or interactive_timeout vs wait_timeout confusion) reaps connections early.
SHOW VARIABLES WHERE Variable_name IN ('wait_timeout','interactive_timeout','max_allowed_packet');
# e.g. HikariCP: maxLifetime = min(25min, wait_timeout - 1min)
SET GLOBAL max_allowed_packet = 268435456; # and the client driver's limit
# check LB/proxy idle timeout > wait_timeout, or enable TCP keepalives
The gold rule: client pool maxLifetime must be shorter than server wait_timeout. Reconnecting on failure hides the bug; sizing the pool lifetime correctly removes it.
The TCP connect succeeds but the handshake stalls: DNS reverse-lookup on the server (skip_name_resolve), a saturated max_connections queue, or a middlebox dropping idle streams. connect_timeout on the server and the driver's connect timeout are different knobs.
Connection churn: apps opening connections per-request exhaust the backlog. Pool connections, and check Threads_connected vs max_connections plus the Aborted_connects counter trend during the failure window.
Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.
Browse the template store →One-time. Yours to modify. Instant download from the NinjaOps template store.