
MySQL returns ERROR 1040 (HY000): Too many connections when every available connection slot is occupied and a new client tries to connect. MySQL allocates a fixed pool of connection slots at startup, controlled by the max_connections system variable. When all slots are full, MySQL rejects the incoming connection outright — it does not queue it.
There are two distinct root causes, and it is important to distinguish between them before reaching for a fix:
Legitimate traffic growth. Your application is genuinely receiving more concurrent requests than your current max_connections can handle. In this case raising the limit — provided the server has enough RAM — is the correct response.
Connection leaks. Your application code is opening connections and not closing them properly — or it is opening a new connection for every query instead of reusing a pool. Each leaked connection occupies a slot indefinitely until MySQL's wait_timeout closes it (default: 28,800 seconds, i.e. 8 hours). Raising max_connections in this scenario only defers the crash — you must fix the leak.
On a typical WordPress server, the most common trigger is a combination of both: a burst of traffic hits the site during a slow query storm, PHP-FPM spawns additional workers each opening their own MySQL connection, and the default max_connections = 151 is exhausted within seconds.
Before changing any configuration, get a baseline. Log in to the MySQL shell and run the following queries to see where things stand:
Pay attention to Max_used_connections. If it is close to your current max_connections, you have been operating near the ceiling and a small traffic spike will trigger the error. If Connection_errors_max_connections is non-zero, connections have already been refused.
The SHOW PROCESSLIST output is also valuable: look for large numbers of connections in the Sleep state. A healthy server has a handful of sleeping connections. Hundreds of them are a clear signal of connection leaks — PHP scripts that opened a connection and never explicitly closed it, leaving MySQL to time it out.
You can raise max_connections without restarting MySQL by setting it dynamically. This is useful for an immediate fix during an incident. The change takes effect instantly but will revert on next restart unless you also write it to the config file.
Each MySQL connection consumes approximately 1–4 MB of RAM depending on the query buffers assigned to it. Before raising max_connections, confirm your server has enough free RAM. A rough formula: max_connections × per_connection_memory ≤ available RAM − InnoDB buffer pool. Setting max_connections = 500 on a 1 GB VPS will cause OOM kills, not fewer errors.
Note that MySQL reserves one extra connection above max_connections for users with the SUPER (or CONNECTION_ADMIN) privilege. This is intentional — it means an administrator can always log in to diagnose the problem even when the limit is fully exhausted by application connections.
If SHOW PROCESSLIST shows many connections in the Sleep state, the root cause is leaking connections and a higher max_connections is only a band-aid. The correct fix is a two-pronged approach: shorten wait_timeout so MySQL reclaims idle connections faster, and fix the application code so it closes connections explicitly.
The SELECT CONCAT query generates a list of KILL statements. Copy the output and run each line to immediately free up those slots. This is a one-time recovery action — not a permanent solution.
On the application side, the most common causes of leaked connections in PHP are:
Using mysql_connect() without a connection pool. Every PHP request opens a fresh connection. With 50 concurrent PHP-FPM workers, that is 50 simultaneous connections, each held open for the duration of the request and its opcache lifecycle.
WordPress with poorly written plugins. Some plugins open additional database connections using new wpdb() instead of using the global $wpdb instance. Audit active plugins — deactivate them one by one while watching Threads_connected to identify the culprit.
Long-running scripts or background jobs that hold a connection open for the entire duration of the job, blocking slots for minutes at a time.
MySQL creates a new operating system thread for each connection. Spawning threads is expensive — under high connection churn it measurably impacts throughput. The thread_cache_size variable controls how many threads MySQL keeps ready in a cache after a connection closes, so the next connection can reuse a cached thread instead of spawning a new one.
For MariaDB users, the Thread Pool plugin is a more robust solution. Instead of a 1:1 thread-per-connection model, the thread pool uses a small number of worker threads that handle many connections. This drastically reduces the impact of connection spikes. On Ubuntu 24.04 with MariaDB, enable it by adding the following to /etc/mysql/mariadb.conf.d/50-server.cnf:
The thread pool is especially effective on servers running WordPress with many simultaneous short-lived PHP-FPM connections. A server that was crashing at 150 connections can comfortably handle 500+ concurrent connections with thread pooling enabled, because each worker thread processes multiple connections rather than blocking on one.
If you manage your server through CloudStick, you can view real-time CPU and memory usage directly in the dashboard to monitor the impact of connection setting changes before and after. This makes it straightforward to validate whether raising max_connections is actually straining your available RAM.
Dynamic SET GLOBAL changes are lost on restart. To persist them, write the values to the MySQL configuration file. On Ubuntu 24.04 with MariaDB (the stack CloudStick installs), the right file is /etc/mysql/mariadb.conf.d/50-server.cnf. For upstream MySQL the file is typically /etc/mysql/mysql.conf.d/mysqld.cnf.
Add or update the following block under the [mysqld] section. The values below are conservative defaults suitable for a server with 2–4 GB of RAM running WordPress workloads:
After saving the file, validate the configuration and reload the service:
Note that systemctl reload sends a SIGHUP to MariaDB, which causes it to re-read the config file and apply most variable changes without a full restart. However, some variables — including thread_handling and thread_pool_size — require a full restart because they are initialised at startup. If you enabled the thread pool, use systemctl restart mariadb and schedule it for a low-traffic window.
After applying the permanent fix, monitor Threads_connected and Max_used_connections over the next 24–48 hours. A well-configured server should keep Max_used_connections well below 70% of max_connections during normal peak traffic. If usage keeps climbing toward the ceiling, your traffic has genuinely outgrown the server spec and it is time to either vertically scale the database or move to a dedicated database server.
The "Too Many Connections" error is one of the most preventable MySQL failures. The default limit of 151 is deliberately conservative — MySQL's documentation notes it was chosen to avoid overwhelming servers with limited RAM. With proper configuration and a small amount of connection hygiene on the application side, most production servers can handle several times that number without any stability issues.

