How to Size a MySQL Connection Pool
Calculate a safe MySQL pool ceiling across app replicas, then tune it with database and application metrics instead of guessing.
On this page
There is no universal connection-pool size that fits every MySQL workload. First calculate the maximum your server can safely accept across all application instances. Then load-test smaller pool limits and choose the value that meets throughput and latency goals without saturating MySQL.
An application pool reuses client connections; it does not increase MySQL’s max_connections limit. MySQL permits one additional connection for a privileged administrator, but application pools must fit within the configured ordinary connection budget. See MySQL’s max_connections documentation and too-many-connections guidance.
1. Find the effective server and account limits
From an authorized connection, check the global connection limit and current usage:
SHOW GLOBAL VARIABLES LIKE 'max_connections';
SHOW GLOBAL STATUS
WHERE Variable_name IN (
'Threads_connected',
'Max_used_connections',
'Connection_errors_max_connections'
);
Threads_connected is current use. Max_used_connections is the server’s simultaneous-connection high-water mark since startup, but FLUSH STATUS resets it to current use. Connection_errors_max_connections counts connections refused at the global limit; compare that counter before and after a test or incident, and account for FLUSH STATUS, which can reset status counters. These are not time-series metrics. Also confirm the effective max_connections value, which can be constrained by open_files_limit.
An account may have a lower simultaneous-connection limit than the server. Check the default and, from a session using the affected account, its initialized limit:
SHOW GLOBAL VARIABLES LIKE 'max_user_connections';
SHOW SESSION VARIABLES LIKE 'max_user_connections';
A nonzero per-account MAX_USER_CONNECTIONS value takes precedence; zero uses the global default, and if both are zero there is no per-account cap. The limit applies to the matching MySQL user@host account, which may be shared by several app instances. See MySQL account resource limits and Error 1203: Too Many User Connections.
2. Calculate an upper budget across every instance
Start with the effective server limit, then subtract peak connections needed by other workloads and explicit headroom for bursts, maintenance, and deployments:
application pool budget
= max_connections
- peak connections from other workloads
- reserved headroom
Add the maximum pool capacity for every independently running app replica, worker, scheduled job, and service that connects to the same server. Count the peak replica count during rolling deployments if old and new instances can overlap. The planned application total must remain at or below the budget. Treat the result as a ceiling, not a target to fill.
When calculating the “other workloads” subtraction, exclude the application pools you are sizing; count each connection in either that subtraction or the planned pool total, never both.
For example, suppose max_connections is 240, other workloads can use 50 connections, and you reserve 30 for bursts and operations. The application budget is at most 160. Eight replicas with a pool maximum of 18 can open up to 144 connections, leaving 16 connections inside that budget. If a deployment can temporarily run ten replicas, that same pool maximum could require 180 connections; lower it, reduce other usage, or revise the capacity plan before the rollout.
For each account, do the same comparison using its effective max_user_connections value and all pools using the same user@host. The global and account-level limits are separate constraints, so the tighter budget is the one that matters. Use the MySQL connection pool budget estimator and account connection budget estimator to check the arithmetic.
3. Tune with a representative workload
Begin with a conservative pool maximum that fits both budgets. Increase load gradually using representative queries, transaction lengths, and data volumes. Measure application request latency and pool wait time alongside MySQL throughput, active connections, running threads, and refused connections. Stop increasing the pool when throughput stops improving or latency, lock waits, or resource pressure worsen.
Do not set the pool maximum equal to web-user concurrency: most requests are not using a database connection at the same instant. Long transactions hold connections longer, and oversized pools can push more work onto a database that is already saturated. Pool-sizing guidance from HikariCP also recommends load-testing around an initial value; its examples are not a universal formula for MySQL or every application.
Use your pool library’s documented maximum to count physical MySQL connections. For example, HikariCP defines maximumPoolSize as the maximum number of actual connections to the database. Review the behavior of your own driver or pool, including minimum idle connections and acquisition timeouts.
4. Keep connection pools separate from server thread pools
The application pool limits how many client connections each app instance can open. MySQL’s server-side Thread Pool manages server execution threads under concurrency; it does not raise max_connections or replace the application pool. Consider it only after measurements show execution-thread contention. See MySQL 26.7 Thread Pool guidance.
If users receive Error 1040, the global connection limit has been reached; follow MySQL Error 1040 troubleshooting. If MySQL names an account limit, follow Error 1203 troubleshooting. For a broader overview of limits and browser-based estimates, see MySQL Capacity Planning.