MySQL Connection Pooling with ProxySQL and WordPress

On high-traffic WordPress sites, the cost of establishing a new TCP connection to MySQL for every PHP request becomes a bottleneck long before the query itself is slow. ProxySQL acts as a transparent connection pool in front of MySQL: PHP connects to ProxySQL on port 6033, and ProxySQL multiplexes those short-lived PHP connections into a small pool of long-lived MySQL connections.

Problem: PHP-FPM opens a new database connection for every worker process and holds it only for the duration of a request — under high concurrency, MySQL exhausts max_connections and returns "Too many connections" errors even when queries themselves are fast.

Solution: Deploy ProxySQL between PHP-FPM and MySQL to multiplex hundreds of short-lived PHP connections onto a smaller pool of persistent backend connections. Configure a connection pool rule in proxysql.cnf, point DB_HOST in wp-config.php at ProxySQL's port 6033, and monitor pool usage with the ProxySQL admin interface on port 6032.


The configuration below installs ProxySQL, defines a hostgroup for the primary MySQL server, sets pool size limits, and shows the wp-config.php change required to route WordPress through the proxy.


# Install ProxySQL (Ubuntu/Debian)
wget https://github.com/sysown/proxysql/releases/download/v2.6.3/proxysql_2.6.3-ubuntu22_amd64.deb
sudo dpkg -i proxysql_2.6.3-ubuntu22_amd64.deb
sudo systemctl enable --now proxysql

# Connect to ProxySQL admin interface (default password: admin)
mysql -u admin -padmin -h 127.0.0.1 -P 6032


-- Inside ProxySQL admin (port 6032)

-- 1. Add the real MySQL backend
INSERT INTO mysql_servers(hostgroup_id, hostname, port, max_connections)
VALUES (0, '127.0.0.1', 3306, 200);

-- 2. Add the WordPress DB user
INSERT INTO mysql_users(username, password, default_hostgroup)
VALUES ('wp_user', 'secret', 0);

-- 3. Set connection-pool limits
UPDATE global_variables
SET variable_value = '50'
WHERE variable_name = 'mysql-max_connections';

UPDATE global_variables
SET variable_value = '8'
WHERE variable_name = 'mysql-free_connections_pct';

-- 4. Persist and load to runtime
SAVE MYSQL SERVERS TO DISK;   LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;     LOAD MYSQL USERS TO RUNTIME;
SAVE GLOBAL VARIABLES TO DISK; LOAD MYSQL VARIABLES TO RUNTIME;


// wp-config.php  — point WordPress at ProxySQL instead of MySQL directly
define( 'DB_HOST',     '127.0.0.1:6033' );   // ProxySQL port
define( 'DB_NAME',     'helloadmin' );
define( 'DB_USER',     'wp_user' );
define( 'DB_PASSWORD', 'secret' );


NOTE: ProxySQL's multiplexing breaks if the PHP code uses MySQL session state (temporary tables, SET variables). If your plugins rely on session variables, set mysql-multiplexing=0 in ProxySQL or route those queries to a dedicated hostgroup with multiplexing disabled.