DATABASES
June 29, 2026

How to Fix "Too Many Connections" MySQL Errors

8 min read
Author
CloudStick Team
WordPress Engineer
Share this article
How to Fix Too Many Connections MySQL Errors
CloudStick
Stop MySQL From Turning Visitors Away

What Causes the "Too Many Connections" Error

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.

Check Your Current Connection Limits and Usage

Before changing any configuration, get a baseline. Log in to the MySQL shell and run the following queries to see where things stand:

# Log in as root
mysql -u root -p
-- Current limit
SHOW VARIABLES LIKE 'max_connections';
-- Peak connections ever reached since last restart
SHOW STATUS LIKE 'Max_used_connections';
-- Connections refused because the limit was hit
SHOW STATUS LIKE 'Connection_errors_max_connections';
-- Currently open connections (one row per connection)
SHOW PROCESSLIST;
-- Threads connected right now
SHOW STATUS LIKE 'Threads_connected';

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.

Raise max_connections Without Crashing the Server

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.

PREREQUISITE

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.

# Apply immediately without restart (survives until next restart)
SET GLOBAL max_connections = 300;
# Verify it took effect
SHOW VARIABLES LIKE 'max_connections';
# Also raise the per-user limit if needed (0 = unlimited)
SET GLOBAL max_user_connections = 0;

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.

Find and Fix Connection Leaks

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.

-- Check current timeout values
SHOW VARIABLES LIKE '%timeout%';
-- Reduce the idle timeout to 60 seconds (dynamic)
SET GLOBAL wait_timeout = 60;
SET GLOBAL interactive_timeout = 60;
-- Kill all current sleeping connections manually
-- (run this once to reclaim slots during an incident)
SELECT CONCAT('KILL ', id, ';') FROM information_schema.processlist
WHERE command = 'Sleep' AND time > 60;

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.

Tune Connection Pooling and Thread Cache

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.

-- Check thread cache efficiency
SHOW STATUS LIKE 'Threads_created';
SHOW STATUS LIKE 'Connections';
-- If Threads_created / Connections > 0.05 (5%), increase thread_cache_size
-- Check current cache size
SHOW VARIABLES LIKE 'thread_cache_size';
-- Raise it dynamically
SET GLOBAL thread_cache_size = 32;

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:

[mysqld]
thread_handling = pool-of-threads
thread_pool_size = 16 # match CPU core count
thread_pool_max_threads = 500
thread_pool_idle_timeout = 60

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.

TIP

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.

Making the Fix Permanent in mysqld.cnf

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.

# Back up the config before editing
sudo cp /etc/mysql/mariadb.conf.d/50-server.cnf \
/etc/mysql/mariadb.conf.d/50-server.cnf.bak
sudo nano /etc/mysql/mariadb.conf.d/50-server.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:

[mysqld]
# Connection limits
max_connections = 300
max_user_connections = 0
# Idle connection cleanup
wait_timeout = 120
interactive_timeout = 120
# Thread cache
thread_cache_size = 32
# Connection error tolerance
max_connect_errors = 100000

After saving the file, validate the configuration and reload the service:

# Test configuration for syntax errors
sudo mysqld --validate-config
# Reload MariaDB (graceful — does not drop active connections)
sudo systemctl reload mariadb
# Confirm the new values are live
mysql -u root -p -e "SHOW VARIABLES LIKE 'max_connections';"

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.

Leave a comment
Full Name
Email Address
Message
Contents