ERROR 1040 (HY000): Too many connections is returned by MySQL when a new client attempts to connect and the server has already reached the max_connections limit. The connection is refused immediately — the server does not queue it or wait for a slot to open.
Impact
Every refused connection surfaces as an application error. If the application retries immediately without backoff, it can spike the CPU of both the application servers and MySQL while achieving nothing. In HTTP services the result is a cascade: a brief traffic spike causes connection refusals, which cause request failures, which cause retries, which further exhaust the connection limit. MySQL reserves one administrative connection above max_connections for users with the CONNECTION_ADMIN privilege (root by default), so a DBA can always log in to investigate even when the server is full.
Common Causes
max_connectionsset too low for the actual number of application threads that open connections- Connection pool misconfigured with a pool size larger than
max_connectionsdivided by the number of application instances - Connection leak: application opens connections but never closes or returns them to the pool (missing
close(), exception bypassing cleanup, missingfinally/context manager) - Long-running queries or transactions holding connections idle for minutes
- Spike in traffic without autoscaling on the application tier
- Deployments or rolling restarts that briefly double the number of application instances (and their pools)
- Monitoring or migration tools opening persistent connections not accounted for in sizing
wait_timeout/interactive_timeoutset too high, so idle connections accumulate- Third-party integrations (analytics, BI tools) opening connections outside the pool
- Replicas or read-only users connecting to the primary under misdirected load
Troubleshooting and Resolution Steps
Verify the current limit and peak usage:
SHOW VARIABLES LIKE 'max_connections'; SHOW GLOBAL STATUS LIKE 'Max_used_connections'; SHOW GLOBAL STATUS LIKE 'Threads_connected'; SHOW GLOBAL STATUS LIKE 'Connection_errors_max_connections';Max_used_connectionsis the historical peak since the last restart. If it is close tomax_connections, you have been near the limit before.Connection_errors_max_connectionsis the count of times clients were refused.See every current connection:
SELECT user, host, db, command, time, state, LEFT(info, 100) AS query FROM information_schema.PROCESSLIST ORDER BY time DESC;Group by user and command to find which application is consuming the most slots:
SELECT user, command, COUNT(*) AS cnt, MAX(time) AS max_time_s FROM information_schema.PROCESSLIST GROUP BY user, command ORDER BY cnt DESC;Identify idle connections that are just sitting open:
SELECT user, host, db, time AS idle_s FROM information_schema.PROCESSLIST WHERE command = 'Sleep' ORDER BY time DESC LIMIT 50;A large number of
Sleepconnections with hightimevalues indicates eitherwait_timeoutis too generous or connections are being leaked.Raise
max_connectionsas immediate relief:-- In-session (takes effect immediately, lost on restart) SET GLOBAL max_connections = 500; -- Persist across restarts (MySQL 8.0+) SET PERSIST max_connections = 500;As a rule of thumb:
max_connectionsshould not exceedavailable_RAM_MB / 4for general workloads, because each connection carries its own per-thread buffer allocations (sort_buffer_size,join_buffer_size, etc.). Do not simply set it to a very large number without also accounting for memory.Reclaim idle connections faster by lowering
wait_timeout:-- Current values SHOW VARIABLES LIKE 'wait_timeout'; SHOW VARIABLES LIKE 'interactive_timeout'; -- Lower them (seconds) SET GLOBAL wait_timeout = 60; SET GLOBAL interactive_timeout = 60; SET PERSIST wait_timeout = 60;The default of 28,800 s (8 hours) keeps idle connections alive far longer than any application needs. 60–300 seconds is typical for OLTP services.
Size the thread cache to avoid thread-creation overhead on reconnects:
SHOW VARIABLES LIKE 'thread_cache_size'; SHOW GLOBAL STATUS LIKE 'Threads_created'; SHOW GLOBAL STATUS LIKE 'Connections'; -- If Threads_created / Connections > 0.01, the cache is too small SET GLOBAL thread_cache_size = 50;Audit the connection pool configuration. For HikariCP (Java):
# Total pool slots across all instances must stay under max_connections # leaving room for admins, monitoring, and replication threads maximumPoolSize=20 minimumIdle=5 idleTimeout=60000 # ms — return idle connections after 60 s connectionTimeout=3000 # ms — fail fast if pool is exhausted maxLifetime=1800000 # ms — recycle connections every 30 minFor connection pools in general:
instances × pool_max_size + overhead ≤ max_connections.Use ProxySQL to multiplex application connections: ProxySQL sits between your application and MySQL and multiplexes many application-side connections onto a smaller number of backend connections, effectively decoupling the application's concurrency from MySQL's connection limit. This is the standard solution when you have many short-lived microservice instances each with a pool.
Check for connection leaks in the application. Common patterns in Python (SQLAlchemy):
# Leaky — if something raises, connection is never returned conn = engine.connect() result = conn.execute(text("SELECT ...")) conn.close() # Safe — context manager guarantees return to pool with engine.connect() as conn: result = conn.execute(text("SELECT ..."))In Django: using
django.db.connectiondirectly outside a view that has theCONN_MAX_AGEsetting set to 0 can leave connections stranded. SetCONN_MAX_AGEto a short positive value or 0 (close after each request) and verify withSHOW STATUS LIKE 'Threads_connected'under load.Kill idle connections immediately (emergency measure only — prefer fixing the root cause):
-- Generate KILL statements for all Sleep connections idle > 120 s SELECT CONCAT('KILL ', id, ';') FROM information_schema.PROCESSLIST WHERE command = 'Sleep' AND time > 120;Copy and run the output. In MySQL 8.0 you can also use
KILL CONNECTION idor rely onwait_timeoutafter you lower it.Check the Performance Schema for connection history (MySQL 8.0+):
SELECT user, host, current_connections, total_connections FROM performance_schema.accounts ORDER BY total_connections DESC;This shows which user/host pair has opened the most connections over the server's lifetime, useful for identifying misdirected traffic.
Additional Information
- MySQL always reserves one extra connection above
max_connectionsfor users withCONNECTION_ADMIN(8.0+) orSUPER(5.7). This is the only way to log in when the limit is hit. Threads_connected(SHOW STATUS) is the current count;Max_used_connectionsis the historical peak. Monitor both.- Memory consumption per connection is dominated by per-thread sort and join buffers: a rough lower bound is
read_buffer_size + read_rnd_buffer_size + sort_buffer_size + join_buffer_size + binlog_cache_size, which can be 4–16 MB per thread by default. Settingmax_connections = 10000on a server with 16 GB RAM will cause OOM kills. - Galera Cluster, Group Replication, and read replicas each use their own background connections to the primary; account for these in your connection budget.
performance_schema.events_waits_currentcan show individual thread waits including lock waits and I/O, useful for diagnosing why connections are taking so long that new ones pile up.
Frequently Asked Questions
Q: Can I set max_connections to a very large number to avoid ever hitting the limit?
A: No. Each connection allocates per-thread memory, and MySQL does not cap that allocation. Setting max_connections beyond what your RAM can support causes the OS to OOM-kill the process. A connection pool in front of MySQL is the right solution for high concurrency.
Q: My pool size is 10 and I have 20 instances — that's 200 connections. max_connections is 500. Why am I still seeing error 1040?
A: Check monitoring tools, cron jobs, replication threads, and any direct database connections from scripts or BI tools that operate outside the pool. SELECT COUNT(*) FROM information_schema.PROCESSLIST gives the real count.
Q: After I raise max_connections, the error goes away but the database slows down. Why?
A: More concurrent connections mean more lock contention, context switching, and buffer pool pressure. The right fix is a connection pool with a maximum that matches the database's actual concurrency capacity — usually much lower than the number of application threads.
Q: Does lowering wait_timeout disconnect sessions that are in the middle of a transaction?
A: No. wait_timeout applies only to connections in the Sleep state (idle, not executing a query). An active transaction is not affected.
Q: We use serverless functions — each invocation opens a new connection. What do we do?
A: Use a connection pooler that can be accessed over TCP, such as PlanetScale's connection pooling, Amazon RDS Proxy, or ProxySQL. Alternatively, use mysql2 (Node) or aiomysql (Python) with a module-level pool that persists across warm invocations.
Q: Is there a way to queue connection attempts instead of immediately refusing them?
A: MySQL does not have a built-in queue. ProxySQL has a connection queue (max_connections at the proxy level, with queuing backed by its own pool). RDS Proxy also queues requests up to a configurable timeout.