Logo
WP Fix by Blimx

MySQL max_connections Tuning for WordPress

Actualizado:
DatabaseTuning

Why max_connections matters

Every WordPress request that touches the database opens a MySQL connection. If MySQL's max_connections limit is exceeded, new requests get rejected:

mysqli_connect(): (HY000/1040): Too many connections

WordPress logs this as "Error establishing database connection."

Set the limit too low: traffic spikes overwhelm you. Set too high: MySQL runs out of memory and crashes.

How many connections do you actually need

MySQL allocates memory per connection. Each holds 1-30MB.

Formula:

max_connections Γ— per_connection_memory + base_memory ≀ available RAM

For typical WordPress: - per_connection_memory β‰ˆ 4-8 MB - base_memory β‰ˆ 60-80% of total RAM (mostly innodb_buffer_pool)

Practical rule:

max_connections = (Total RAM Γ— 0.20) / per_connection_memory

For 8GB RAM with 6 MB/connection:

max_connections = (8192 Γ— 0.20) / 6 β‰ˆ 270

So 250-300 max_connections is reasonable for an 8GB server.

Match to PHP-FPM workers

grep pm.max_children /etc/php/8.1/fpm/pool.d/www.conf

If pm.max_children = 50, you have at most 50 simultaneous PHP requests.

max_connections = pm.max_children + 20

For pm.max_children=50, set max_connections=70-100.

Detecting current usage

SHOW STATUS LIKE 'Max_used_connections';
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Threads_running';

If Max_used_connections consistently 80%+ of max_connections, need more capacity or fewer connections.

Setting max_connections

In /etc/mysql/my.cnf:

[mysqld]
max_connections = 200

Restart MySQL (or SET GLOBAL max_connections = 200; for live).

Tuning per-connection memory

If you can't reduce concurrent connections:

[mysqld]
sort_buffer_size = 256K
read_buffer_size = 128K
read_rnd_buffer_size = 256K
join_buffer_size = 256K

WordPress queries don't need large buffers. Reducing to 256K saves memory.

Configuring wait_timeout

Idle connections still consume a slot. wait_timeout controls how long.

Default: 28800 (8 hours). Way too long.

[mysqld]
wait_timeout = 60
interactive_timeout = 600

wait_timeout=60 frees up slots quickly. Often the highest-impact tuning change.

Persistent connections caveat

WordPress doesn't use persistent connections by default. Don't enable them.

Check wp-config.php:

// REMOVE if present:
define('DB_PERSISTENT', true);

And php.ini:

mysqli.allow_persistent = Off

Handling sudden spikes

ProxySQL β€” sits between PHP and MySQL. PHP connects to ProxySQL (cheap). ProxySQL pools real connections. Allows 5x concurrency.

Rate limiting β€” Cloudflare or Nginx rejects excess requests at the edge.

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
    server {
        location / {
            limit_req zone=mylimit burst=20 nodelay;
        }
    }
}

Monitoring max_connections

# Cron: alert if connections > 80%
0 * * * * /var/www/yoursite/scripts/check-mysql-conn.sh
#!/bin/bash
MAX=$(mysql -BNe "SHOW VARIABLES LIKE 'max_connections';" | awk '{print $2}')
CURRENT=$(mysql -BNe "SHOW STATUS LIKE 'Threads_connected';" | awk '{print $2}')
THRESHOLD=$((MAX * 80 / 100))
if [ "$CURRENT" -gt "$THRESHOLD" ]; then
    echo "MySQL connections at $CURRENT / $MAX" | mail -s "Alert" admin@yoursite.com
fi

Common mistakes

  • Setting max_connections to 5000 β€” wastes memory, doesn't help
  • Not adjusting wait_timeout β€” connections pile up
  • Tuning without measuring β€” don't know what you need
  • Restarting MySQL during business hours β€” use SET GLOBAL for live changes

When to call a specialist

MySQL tuning is part of every performance audit. Often we find a server with max_connections=300 and pm.max_children=10 β€” wasting RAM on slots that will never be used.

MySQL tuning as part of speed recovery. For broader work see speed recovery.