MySQL ERROR 1040 Too many connections — Diagnose and Fix
Diagnose MySQL ERROR 1040 by measuring Threads_connected against max_connections, inspecting processlist sleepers, then fixing leaks, wait_timeout, and pool sizing.
Symptoms
- ERROR 1040 (HY000): Too many connections
- New application requests fail while existing sessions continue to work
- Threads_connected sits at or above max_connections
- Processlist is full of Sleep sessions owned by the application user
Possible causes
- The application pool opens more connections than the server is sized for
- Connections leak because code paths never close them or a pool has no maximum
- wait_timeout is high and abandoned sessions stay Sleep for hours
- A traffic spike, cron job, or reporting tool created a second pool against the same database
Diagnosis steps
Compare current connections with the configured ceiling
mysql -uroot -p -e "SHOW STATUS LIKE 'Threads_connected'; SHOW STATUS LIKE 'Threads_running'; SHOW VARIABLES LIKE 'max_connections'; SHOW VARIABLES LIKE 'wait_timeout';"Interpretation
Threads_connected near max_connections confirms exhaustion. Threads_running much lower means most sessions are idle, which points to pooling or leaks rather than CPU load.
Group sessions by user, host, and state
mysql -uroot -p -e "SELECT user, host, db, command, COUNT(*) AS sessions, MAX(time) AS max_idle FROM information_schema.processlist GROUP BY user, host, db, command ORDER BY sessions DESC;"Interpretation
Many Sleep rows from one service indicate leaked or oversized pools. Long Query rows from a single host suggest a runaway report or lock wait.
Find the oldest idle sessions
mysql -uroot -p -e "SELECT id, user, host, db, command, time, state, LEFT(info, 60) AS query FROM information_schema.processlist WHERE command = 'Sleep' ORDER BY time DESC LIMIT 20;"Interpretation
Idle times close to wait_timeout show sessions that will soon expire. Uniform idle times across hundreds of rows usually mean a pool that keeps opening new connections.
Use the administrative connection when the normal limit is reached
mysql --admin -uroot -p -e "SELECT id, user, host, command, time FROM information_schema.processlist ORDER BY time DESC LIMIT 20;"Interpretation
The admin interface bypasses max_connections on MySQL 8.0.14 and later, so you can inspect the server without killing an application session.
Root cause
MySQL admits at most max_connections simultaneous client sessions, with one extra reserved for users holding the CONNECTION_ADMIN privilege. When every slot is occupied, new TCP handshakes complete but the server returns ERROR 1040 before authentication. Idle Sleep sessions still count against the limit, so a pool that never releases connections can exhaust the server without any slow query.
Fix
Right-size each application pool and cap it well below max_connections divided by the number of replicas. Close connections in finally blocks, set a sensible wait_timeout, and put a proxy such as ProxySQL in front when many clients share one server. Raise max_connections only after checking memory and thread overhead, since each session consumes per-thread buffers.
Risk note
Killing sessions with KILL CONNECTION rolls back their transaction and can interrupt batch work. Raising max_connections increases memory use and context switching; it does not repair a leak. The extra administrative slot does not help if the OS file descriptor limit is also exhausted.
Verify the fix
Watch Threads_connected over a full traffic cycle and confirm it stays below the configured pool total. Reconnect from an application replica during peak load and verify no ERROR 1040 appears, with Threads_running well under max_connections.
1040 is admission control, not authentication
ERROR 1040 (HY000): Too many connections is returned after the TCP connection is accepted but before the client is authenticated. MySQL has no free session slot, so credentials are never checked. One slot is reserved for accounts with CONNECTION_ADMIN, which is why a DBA can sometimes log in while the application cannot.
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Threads_running';
SHOW VARIABLES LIKE 'max_connections';
If Threads_connected is at the ceiling and Threads_running is low, the sessions are idle rather than busy. That distinction decides whether you need pool tuning or query tuning.
Read the processlist in aggregate
SELECT user, host, db, command, COUNT(*) AS sessions, MAX(time) AS max_idle
FROM information_schema.processlist
GROUP BY user, host, db, command
ORDER BY sessions DESC;
Hundreds of Sleep rows from one host usually mean a pool with no maximum or a framework opening a connection per request. A few long Query rows mean a lock wait or a runaway report holding a slot.
Fix sizing and lifecycle
Set each pool’s maximum explicitly and multiply by replica count before comparing with max_connections. Add wait_timeout and interactive_timeout appropriate to your traffic, close connections in finally blocks, and deploy ProxySQL or MySQL Router when many clients share the server. Increase max_connections only after checking Threads_running and memory headroom, because every session allocates buffers.
When you must reclaim capacity immediately, prefer terminating idle sessions belonging to a known leaky client rather than restarting MySQL.
Verify under load
Run the load test again and sample Threads_connected every few seconds. It should plateau below the sum of pool limits, and a fresh application connection should succeed while traffic is at its peak. Check SHOW GLOBAL STATUS LIKE 'Aborted_connects'; before and after; a rising value means clients still hit the ceiling or fail authentication.