MySQL ERROR 1040 (HY000): Too many connections - causes and fixes
Once Threads_connected reaches max_connections, MySQL returns ERROR 1040 (HY000) to every new connection attempt before authentication. The server is not down; it is full.
This error is usually a symptom. Connections may be leaking from the application, a cache stampede may have flooded the pool, or slow queries may be holding slots open longer than expected. MySQL reserves one extra connection for users with CONNECTION_ADMIN (or the deprecated SUPER privilege). If that slot is free, an operator can still connect. If an app user has taken it, you may need to restart.
Distinguishing a connection leak from genuine overload is the first decision. High Threads_connected with low Threads_running means idle connections are piling up. High Threads_connected with high Threads_running means active queries are stacking up because they cannot finish. The fix depends on the pattern.
flowchart TD
A[ERROR 1040 received] --> B{Threads_running low?}
B -->|Yes| C[Idle connection leak]
B -->|No| D{Threads_running high?}
D -->|Yes| E[Active overload or lock cascade]
D -->|No| F[Transient connection storm]What this means
MySQL limits concurrent connections with the max_connections system variable. The status variable Connection_errors_max_connections increments for each refusal.
Even at the limit, mysqld permits max_connections + 1 connections. The extra slot is reserved for accounts holding CONNECTION_ADMIN (or SUPER in older versions). Do not grant this privilege to application users. Each connection consumes memory for thread stack, sort buffers, join buffers, and net buffers. Raising max_connections without adding RAM trades refusals for OOM risk.
Common causes
| Cause | What it looks like | First thing to check |
|---|---|---|
| Connection leak | Threads_connected near limit, Threads_running low, many Sleep states in SHOW PROCESSLIST | SHOW PROCESSLIST for connections with high Time in Sleep |
| Connection pool oversizing | Sudden spike after deployment; pool max multiplied by instance count exceeds max_connections | Application pool configuration against SHOW VARIABLES LIKE 'max_connections' |
| Slow query or lock cascade | Threads_running high; queries stuck in active states | SHOW PROCESSLIST for long-running active queries; INNODB_TRX for old transactions |
| Idle connection accumulation | Many Sleep connections with Time values above wait_timeout but still open | SHOW VARIABLES LIKE 'wait_timeout' and processlist Time values |
| Application retry storm | Brief spike in Connection_errors_max_connections and Aborted_connects | Application logs for retry loops after a transient error |
Quick checks
-- Check connection saturation ratio
SELECT
(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Threads_connected') AS connected,
(SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'max_connections') AS max_conn;
-- Check active execution concurrency
SHOW GLOBAL STATUS LIKE 'Threads_running';
-- Check if connections are being refused
SHOW GLOBAL STATUS LIKE 'Connection_errors_max_connections';
-- See current connections and states
SHOW PROCESSLIST;
-- Find long-running transactions
SELECT trx_mysql_thread_id, trx_started,
TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS age_seconds
FROM information_schema.INNODB_TRX
ORDER BY trx_started ASC;
-- Check high-water mark since restart
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
How to diagnose it
- Confirm saturation. If
Threads_connected / max_connectionsis greater than 0.95 andConnection_errors_max_connectionsis increasing, the server is actively refusing connections. - Classify the pattern. If
Threads_runningis a small fraction ofThreads_connected, you have an idle connection leak. If both are high, active work is piling up. - Inspect
SHOW PROCESSLIST. ManySleepentries with highTimepoint to leaked or idle connections. Active queries with highTimepoint to slow execution or blocking. - Check for lock contention. Query
information_schema.INNODB_TRXandperformance_schema.data_lock_waits(MySQL 8.0+) to find blocking transactions. A metadata lock cascade from pending DDL can also fill the pool; checkperformance_schema.metadata_locksif available. - Correlate with changes. Look for recent deployments that changed pool sizes, upstream cache clears that caused stampedes, or new batch jobs.
Metrics and signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
Threads_connected / max_connections | Measures slot saturation | Greater than 0.80 sustained; page at greater than 0.95 |
Connection_errors_max_connections | Counts direct refusals | Any nonzero rate in production |
Threads_running | Distinguishes leak from overload | Low with high Threads_connected indicates leak; high indicates overload |
Max_used_connections | Historical peak for capacity planning | Greater than 0.70 of max_connections trending upward |
Aborted_connects | Precursor or companion to saturation | Rate increasing suddenly |
Fixes
Idle connection leak or excessive Sleep states
Lower wait_timeout to close idle connections faster. This is dynamic but applies only to new sessions:
SET GLOBAL wait_timeout = 300;
Existing idle connections retain the old session value and may not close immediately. Kill them to free slots now:
KILL <id>;
Warning: This terminates the session and rolls back any open transaction.
Tradeoff: Applications that rely on long-lived idle connections may see errors when reusing a dead connection. Fix the application to close connections or validate them on checkout.
Slow queries or lock cascades
Kill the offending query or transaction:
KILL <id>;
Warning: Rolling back a large transaction can be expensive and I/O intensive. If a metadata lock cascade is the cause, killing the blocking transaction or pending DDL unblocks the queue.
Connection pool oversizing
Reduce the per-application-instance pool maximum. Ensure that (pool_max_size * application_instances) stays well below max_connections, leaving at least 20% headroom for spikes and admin access. Aggregate pool limits if many services share one MySQL instance. Connection poolers such as ProxySQL can multiplex many client connections into fewer server connections.
Emergency: temporarily raise the limit
If you need immediate breathing room and have the memory:
SET GLOBAL max_connections = <new_higher_value>;
Warning: You need SYSTEM_VARIABLES_ADMIN (or SUPER) to change this. The change is lost on restart; update my.cnf to persist it. Each connection uses memory. Raising the limit without raising RAM risks OOM.
Prevention
- Size pools with headroom. Aggregate all application pool maxima and keep the total under 70% of
max_connections. - Set
wait_timeoutappropriately. The default of 8 hours retains idle connections indefinitely for many workloads. For stateless apps, 300-600 seconds is usually sufficient. - Reserve the admin slot. Never grant
CONNECTION_ADMINorSUPERto application users. Audit grants regularly. - Monitor the ratio, not the absolute count. Alert on
Threads_connected / max_connectionsgreater than 0.80 and on anyConnection_errors_max_connectionsincrement. - Audit long transactions. Connections with open transactions hold metadata locks and prevent purge. Monitor
INNODB_TRXfor transactions older than a few minutes.
How Netdata helps
Netdata correlates Threads_connected, Threads_running, and Connection_errors_max_connections on one chart to reveal whether the issue is a leak or overload. It alerts on connection saturation ratio and refusal rate without manual status queries. It tracks Max_used_connections trends to expose capacity planning issues before the cliff. InnoDB transaction age and lock wait metrics appear alongside connection data to speed root-cause analysis.







