Every query sent to MySQL requires a network transport channel. Establishing a new TCP connection for each incoming web request quickly causes connection overhead, resulting in worse application performance.
Connection pooling solves this bottleneck by keeping a fixed pool of established connections ready in application memory. Incoming client requests borrow an idle connection, send their SQL query over the existing socket, and return the connection to the pool upon completion.
MySQL Connection Pool Architecture
Pre-allocated TCP sockets multiplexing concurrent transactions
Why not spin up thousands of connections?
A connection is not free. Each one costs MySQL a thread and several megabytes of memory, so a big pool makes every query slower instead of faster.
Threads: MySQL runs one operating-system thread per connection. Two hundred connections means two hundred threads, and every running query competes for CPU time. Once the number of running queries passes the number of CPU cores, the operating system spends its time switching between threads instead of running queries. Throughput falls.
Memory: Each connection allocates buffers for sorting, joining, and reading data — often several megabytes. These buffers are allocated only when a query needs them, so memory use is spiky. Four hundred idle connections may fit comfortably in memory, then one busy period with large sorts on many connections at once can exhaust the server's memory.
How many connections is realistic?
A common starting point for transactional workloads is pool size = CPU cores × 2–10, tuned up for workloads that wait on disk or network. On a 4-core server, tens of connections doing useful work beats hundreds of connections fighting each other.
Connections vs throughput
4-core MySQL · drag the slider — throughput peaks near cores × 6, then falls
Drag the slider — or replay the tour
What the server feels
The pool always looks healthy — drag past the sweet spot and watch the MySQL board drown
Drag the slider — or replay the tour
War Story: Connection Pool Exhaustion
Some microservice at work had a SELECT * FROM table; hidden inside it on an infrequently used codepath. This service eventually received a traffic surge that led to connection pool exhaustion and service disruption. This was due to the full table scan taking 30+ seconds against a very large table, and the same query began hogging all connections in the pool.
Connection Pool Exhaustion
Every socket ends up running the same 30s full table scan
