SYSTEMS OPERATIONAL
Troubleshooting

MySQL "Too Many Connections" Error: Causes and the Fix

Getwebup 6 min read

Your site is fine one minute, then MySQL starts throwing Error establishing a database connection or, if you're looking at the raw log, the far more honest ERROR 1040 (HY000): Too many connections. It usually shows up during a traffic spike, a cron pile-up, or right after you add a new site to a busy server. Here's what's actually happening and how to fix it without just restarting MySQL and hoping.

What "too many connections" actually means

MySQL caps how many clients can be connected to it at once. That cap is the max_connections variable, and it exists to protect the server from being overwhelmed — each open connection reserves memory, and MySQL would rather refuse a new connection than let the whole server run out of RAM and crash.

When every connection slot is already in use, the next request — your WordPress site loading a page, a WP-CLI command, phpMyAdmin, whatever — gets rejected. WordPress doesn't know the difference between "wrong password" and "no room at the table," so it shows the same generic database connection error either way. The real cause only shows up in the MySQL error log or when you check the variable directly.

Confirm it's actually a connection limit, not something else

Don't change any config until you've confirmed this is really the issue. SSH in (or use cPanel's Terminal) and run:

mysql -u root -p -e "SHOW VARIABLES LIKE 'max_connections';"
mysql -u root -p -e "SHOW STATUS LIKE 'Threads_connected';"

If Threads_connected is sitting close to or at max_connections, that's your answer. You can also check SHOW STATUS LIKE 'Connection_errors_max_connections'; — a rising, non-zero number confirms connections are actually being refused, not just running high.

On shared cPanel hosting you usually don't have root MySQL access. In that case check cPanel → Metrics → MySQL/MariaDB if your host exposes it, or open a support ticket and ask them to check Threads_connected vs max_connections for your account.

See what's actually holding connections open

If you do have access, this tells you who's eating the slots:

mysql -u root -p -e "SHOW FULL PROCESSLIST;"

Look at the Command and Time columns. A handful of things commonly show up here:

  • Sleep connections sitting for a long time — usually PHP-FPM or Apache keeping connections open longer than they need to, or a plugin not closing its own queries.
  • Many identical queries from the same host — a runaway cron job, a bot hammering a search page, or a WooCommerce/booking plugin polling the database too aggressively.
  • Locked queries — a slow, unindexed query holding a table lock while dozens of others queue up behind it.

Fixes, from fastest to most durable

1. Clear the immediate backlog

If the site is down right now and you need it back fast, restarting MySQL closes every stale connection at once:

sudo systemctl restart mysql
# or, depending on the distro:
sudo systemctl restart mariadb

This buys you time, not a fix. If nothing else changes, you'll be back here within hours or days.

2. Raise max_connections — carefully

Each connection can use a meaningful chunk of RAM depending on your buffer settings, so don't just set this to 1000 on a 2GB VPS. A safe starting point is 150–200 on a small VPS, higher on larger boxes. Edit your MySQL config:

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
# add or edit under [mysqld]:
max_connections = 200

Restart the service afterward. On cPanel/WHM servers, this lives in WHM → MySQL/MariaDB Configuration instead of editing the file directly — use that UI so your change survives the next cPanel update.

3. Fix the thing actually consuming connections

Raising the limit without addressing the cause just delays the next outage. The usual culprits, in order of how often we see them:

  • PHP-FPM pool sized larger than MySQL can handle. If pm.max_children in your PHP-FPM pool config is 100 and each child can open a DB connection, you can hit 100 connections from PHP alone. Check /etc/php/8.x/fpm/pool.d/www.conf and bring pm.max_children in line with what your MySQL max_connections and available RAM can actually support.
  • A plugin or cron job not closing connections. WP-Cron tasks, backup plugins, and import/export tools are common offenders. Check wp-content/plugins for anything that runs on a tight schedule, and consider moving WP-Cron to a real system cron job so it doesn't fire on every page load.
  • Persistent connections left on. If DB_HOST in wp-config.php is set to something like p:localhost, that colon-prefixed "p:" enables persistent MySQL connections, which don't get released between requests. Remove the p: unless you specifically configured it that way for a reason.
  • Too many sites on one small database server. Each WordPress install on shared MySQL adds its own baseline connection load. If you've added several sites to a small VPS, the fix isn't a config tweak — it's more RAM or a managed database tier.

4. Set a sane wait_timeout

A long wait_timeout lets idle connections sit around doing nothing while still holding a slot. Lowering it clears dead weight faster:

# in mysqld.cnf, under [mysqld]:
wait_timeout = 180
interactive_timeout = 180

180 seconds is a reasonable default for a web app. Don't set this too low if you run long batch jobs or big phpMyAdmin imports — you'll cut those off mid-run instead.

SymptomLikely causeWhere to look
Error appears only during traffic spikesmax_connections too low for real loadSHOW VARIABLES / WHM MySQL config
Error is constant, even at low trafficSomething holding connections openSHOW FULL PROCESSLIST
Started right after adding a pluginPlugin not closing DB connections / polling too oftenDeactivate plugins one by one
Multiple sites on the box affected togetherServer-wide connection ceiling hitPHP-FPM pool size vs max_connections

Prevention: keep it from coming back

  • Monitor Threads_connected over time, not just when things break. Most VPS monitoring tools (or a simple cron script piping to a log) will show you the trend before it becomes an outage.
  • Cap PHP-FPM's pm.max_children to something your server's RAM and MySQL's max_connections can both support — don't size it in isolation.
  • Move WP-Cron off page-load triggering (define('DISABLE_WP_CRON', true); in wp-config.php, paired with a real system cron hitting wp-cron.php every few minutes).
  • Add basic caching (object cache or a page cache) so repeat requests don't all hit MySQL individually.
  • If you're consistently near the ceiling on a VPS, that's a sizing signal, not just a config one — more RAM usually solves this more permanently than tuning alone.

On Getwebup VPS and cPanel plans, our support team can check Threads_connected, PHP-FPM pool sizing, and slow query logs together, since these three usually need to be tuned as a set rather than one at a time.

Frequently asked questions

Is "too many connections" the same as "error establishing a database connection"?

They can look identical to a site visitor because WordPress shows the same generic message for both. The difference is the cause: wrong credentials or a stopped database service versus MySQL actively refusing new connections because it's at its max_connections limit. Check SHOW FULL PROCESSLIST or your MySQL error log to tell them apart.

Is it safe to just raise max_connections as high as possible?

No. Each connection reserves memory, so setting the limit too high on a small VPS can exhaust RAM and crash MySQL entirely instead of just refusing new connections. Raise it in modest steps (for example from 150 to 200) and watch memory usage before going higher.

Why does this happen right after a traffic spike but not during normal browsing?

Under normal load, connections open and close fast enough that you never get near the ceiling. During a spike, more requests arrive than can be served and closed in time, so connections stack up faster than they're released and you hit max_connections.

Can a single plugin really cause this?

Yes. Plugins that poll the database on a tight schedule, run long-running queries without releasing them, or use persistent connections incorrectly can hold connection slots open far longer than a normal page load needs. Deactivating plugins one at a time while watching Threads_connected will usually identify it.

Will restarting MySQL fix this for good?

It clears the immediate backlog by force-closing every connection, so the site comes back up. But if the underlying cause -- an undersized max_connections, a runaway cron job, or an oversized PHP-FPM pool -- isn't addressed, the same error will return.

#mysql #too-many-connections #max-connections #php-fpm #vps #troubleshooting

Keep reading

Chat with Support