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

CauseWhat it looks likeFirst thing to check
Connection leakThreads_connected near limit, Threads_running low, many Sleep states in SHOW PROCESSLISTSHOW PROCESSLIST for connections with high Time in Sleep
Connection pool oversizingSudden spike after deployment; pool max multiplied by instance count exceeds max_connectionsApplication pool configuration against SHOW VARIABLES LIKE 'max_connections'
Slow query or lock cascadeThreads_running high; queries stuck in active statesSHOW PROCESSLIST for long-running active queries; INNODB_TRX for old transactions
Idle connection accumulationMany Sleep connections with Time values above wait_timeout but still openSHOW VARIABLES LIKE 'wait_timeout' and processlist Time values
Application retry stormBrief spike in Connection_errors_max_connections and Aborted_connectsApplication 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

  1. Confirm saturation. If Threads_connected / max_connections is greater than 0.95 and Connection_errors_max_connections is increasing, the server is actively refusing connections.
  2. Classify the pattern. If Threads_running is a small fraction of Threads_connected, you have an idle connection leak. If both are high, active work is piling up.
  3. Inspect SHOW PROCESSLIST. Many Sleep entries with high Time point to leaked or idle connections. Active queries with high Time point to slow execution or blocking.
  4. Check for lock contention. Query information_schema.INNODB_TRX and performance_schema.data_lock_waits (MySQL 8.0+) to find blocking transactions. A metadata lock cascade from pending DDL can also fill the pool; check performance_schema.metadata_locks if available.
  5. 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

SignalWhy it mattersWarning sign
Threads_connected / max_connectionsMeasures slot saturationGreater than 0.80 sustained; page at greater than 0.95
Connection_errors_max_connectionsCounts direct refusalsAny nonzero rate in production
Threads_runningDistinguishes leak from overloadLow with high Threads_connected indicates leak; high indicates overload
Max_used_connectionsHistorical peak for capacity planningGreater than 0.70 of max_connections trending upward
Aborted_connectsPrecursor or companion to saturationRate 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_timeout appropriately. 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_ADMIN or SUPER to application users. Audit grants regularly.
  • Monitor the ratio, not the absolute count. Alert on Threads_connected / max_connections greater than 0.80 and on any Connection_errors_max_connections increment.
  • Audit long transactions. Connections with open transactions hold metadata locks and prevent purge. Monitor INNODB_TRX for 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.