max_connections (often 151 by default!) is exhausted. Emergency: raise it or kill sleepers. Durable: connection pooling and fixing leaks.
151 is the MySQL default; a few app servers each with 100-connection pools will exhaust it instantly. SHOW VARIABLES LIKE 'max_connections'; SHOW STATUS LIKE 'Threads_connected';
Apps opening a connection per request without closing, or long-running sleepers: SHOW PROCESSLIST with hundreds of 'Sleep' rows, mostly from one host.
SHOW PROCESSLIST; -- or: SELECT user, host, db, COUNT(*) FROM information_schema.processlist GROUP BY user, host, db ORDER BY 4 DESC;
KILL <id>; -- for confirmed-idle sleepers ; SET GLOBAL max_connections = 300; -- takes effect immediately, resets on restart
# my.cnf [mysqld]: max_connections = 300 -- and budget: each connection ≈ thread stack + sort buffers, check RAM headroom
# ProxySQL or app-level pools sized ~ (cores*2)+spindles; the pool's max must be < mysql's max_connections minus admin headroom
SET GLOBAL wait_timeout = 120; SET GLOBAL interactive_timeout = 120; -- sleepers get reaped sooner
Scale max_connections with RAM: thousands of threads = tens of GB of hidden allocations. Pooling beats a bigger number. Cloud-managed MySQL: check the plan's cap — Provider-managed instances often refuse values above a threshold.
Depends on RAM and per-connection buffers; a common sane range is 300-1000 with pooling in front. Beyond ~1000 raw app connections, you want ProxySQL rather than a bigger ceiling.
Clients open a connection and idle past what they need (no pool eviction, no close). Wait_timeout eventually reaps them — until then each occupies a max_connections slot. Fix the app's pool, or shorten wait_timeout.
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.