MySQL error 1040 "Too many connections" means the server has reached its max_connections limit and is refusing new clients. This guide shows you how to confirm the limit, find which users and hosts are holding connections, raise the limit without starving the server of memory, and fix the leak that caused it.
The fix is usually two parts: a short-term change so your application can connect again, and a longer-term change to wait_timeout or your application's connection handling so the same thing does not happen next week.
Before you start
You need:
- SSH access to your Linux VPS and a user with
sudo. - The MySQL or MariaDB root password (or another account with
SUPERorCONNECTION_ADMIN). - A note of which config file your distribution uses. On Ubuntu and Debian it is
/etc/mysql/mysql.conf.d/mysqld.cnf. On AlmaLinux and Rocky it is/etc/my.cnf.d/mysql-server.cnf. Check withmysqld --verbose --help | grep -A1 "Default options"if you are unsure.
If MySQL is refusing every connection, including yours, restart it from your VPS provider's console or over SSH with sudo systemctl restart mysql (use mariadb on MariaDB hosts). That clears the current sessions and buys you time to make the real change.
Warning: Restarting MySQL drops all open connections and any in-flight transactions. Do it during a quiet period if the database is live.
Confirm the MySQL too many connections error
First, prove the limit is what you think it is. MySQL keeps one spare connection for accounts with SUPER or CONNECTION_ADMIN, so root can usually still get in.
mysql -u root -p -e "SHOW VARIABLES LIKE 'max_connections'; SHOW STATUS LIKE 'Threads_connected'; SHOW STATUS LIKE 'Max_used_connections';"Read the output like this:
max_connectionsis the ceiling. The default is 151 on MySQL 8 and MariaDB.Threads_connectedis how many clients are connected right now.Max_used_connectionsis the high-water mark since the last restart. If it equalsmax_connections, you have hit the ceiling.
You can also check the error log for the exact message, which helps confirm whether it is a connection count problem or a thread creation problem:
sudo tail -n 50 /var/log/mysql/error.logIf you see Can't create a new thread (errno 11) instead of error 1040, the limit is the operating system's process or file-descriptor limit, not max_connections. Check it with:
systemctl show mysql | grep -i limitnofile
ulimit -uFind who is holding the connections
Raising the limit without knowing who is connected just delays the next outage. Open a session and look at the process list:
mysql -u root -pSELECT id, user, host, db, command, time, state, LEFT(info, 80) AS query
FROM information_schema.processlist
ORDER BY time DESC
LIMIT 25;Rows with command = Sleep and a large time value are the usual culprit: an application opened a connection and never closed it. Group them to see which host or user is responsible:
SELECT user, host, COUNT(*) AS conns
FROM information_schema.processlist
GROUP BY user, host
ORDER BY conns DESC;If one web server or one cron job owns hundreds of sleeping sessions, fix that client rather than the server. Common causes are a PHP script using mysqli_connect inside a loop, a Python worker that never calls close, or a pool size set higher than the number of workers.
You can kill a specific runaway session, but only if you are sure it is idle:
KILL 12345;Warning: KILL on an active session rolls back its current transaction. Never kill sessions in bulk on a production database without checking what they are doing first.
Raise max_connections safely
For an immediate fix, change the value at runtime. This survives until the next restart:
SET GLOBAL max_connections = 200;To make it permanent, edit the server config. On Ubuntu or Debian:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnfAdd or change these lines under [mysqld]:
[mysqld]
max_connections = 200
thread_cache_size = 32On AlmaLinux or Rocky, the same block goes in /etc/my.cnf.d/mysql-server.cnf. Then restart:
sudo systemctl restart mysqlWarning: Every connection has its own buffers. Raising max_connections from 151 to 1000 on a small VPS can push MySQL into swap or trigger the OOM killer. Increase it in steps and watch memory with free -m under normal load. See Tune MySQL and MariaDB memory settings for a small VPS before you go large.
thread_cache_size keeps idle threads around so new connections do not pay the cost of creating one. A value between 16 and 64 is reasonable for most VPS workloads.
Fix connection leaks and tune wait_timeout
The default wait_timeout is 28800 seconds — eight hours. That means a forgotten connection occupies a slot for most of a day. For a typical web application, lower it:
[mysqld]
wait_timeout = 300
interactive_timeout = 300wait_timeout applies to non-interactive clients such as PHP and Python. interactive_timeout applies to the mysql command-line client. Setting both keeps behaviour predictable.
Tip: If your application uses persistent connections or a pool, set wait_timeout slightly higher than the pool's idle timeout. Otherwise the pool hands out connections the server has already closed, and users see "MySQL server has gone away".
On the application side, the durable fixes are:
- Use a connection pool with a fixed maximum size, and make sure that maximum multiplied by the number of app workers stays below
max_connections. - Close connections in a
finallyblock or use a context manager so an exception cannot leak one. - Avoid opening a new connection per request when a pool is available.
Apply the config change with a restart, then confirm the new values:
sudo systemctl restart mysql
mysql -u root -p -e "SHOW VARIABLES WHERE Variable_name IN ('max_connections','wait_timeout','interactive_timeout','thread_cache_size');"Check it works
Put the server under realistic load and watch the numbers:
mysql -u root -p -e "SHOW STATUS LIKE 'Threads_connected'; SHOW STATUS LIKE 'Max_used_connections'; SHOW STATUS LIKE 'Aborted_connects';"You want Threads_connected to stay well below max_connections at peak, and Max_used_connections to stop tracking the ceiling. Aborted_connects should stay flat — a rising value means clients are being rejected or failing to authenticate.
Then confirm your application connects normally and that no error 1040 appears in its logs. If you use a monitoring check, point it at SHOW STATUS LIKE 'Threads_connected' and alert at around 80 percent of the limit.
Troubleshooting
- Error 1040 returns within minutes of raising the limit — a client is leaking connections faster than you can raise the ceiling. Re-run the grouped process list query and fix the offending host or user instead of increasing
max_connectionsagain. Can't create a new thread (errno 11)— the OS limit, notmax_connections. RaiseLimitNOFILEfor the service with a systemd drop-in and checkulimit -ufor the MySQL user.- "MySQL server has gone away" after lowering
wait_timeout— your pool is holding connections longer than the server allows. Raisewait_timeoutabove the pool's idle timeout, or enable the pool's connection-validation query. - Root cannot connect either — the reserved connection is already in use. Restart the service from the console, then set a sane
max_connectionsbefore the app reconnects. - Connections pile up only during backups —
mysqldumpholds a long-running session. Schedule backups off-peak and see Automating MySQL backups with mysqldump and cron.
Next steps
- Find the queries that keep connections busy for too long with Find slow queries in MySQL with the slow query log.
- Profile expensive statements using Find high-cost MySQL queries with Performance Schema.
- Size memory and buffers correctly with Tune MySQL and MariaDB memory settings for a small VPS.
