VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
Why Connections Are Expensive
Each MySQL connection is a thread on the server. The cost at connection time:- TCP/TLS handshake
- Authentication (credential check, privilege resolution)
- Session variable initialization
Application-Level Pooling
Most application frameworks and database drivers include built-in connection pools. These maintain a pool of open connections and lend them to application threads on demand. Node.js (mysql2):- pool size: how many persistent connections to maintain
- max overflow / queue: how many extra connections are allowed under burst load
- recycle / timeout: when to close and reopen connections (prevents stale connections from MySQL’s
wait_timeout)
MySQL’s wait_timeout and Stale Connections
MySQL closes idle connections afterwait_timeout seconds (default: 28800 seconds / 8 hours). This applies to non-interactive connections — the kind application pools use. If your pool holds connections longer than this, they go stale and the next query fails with MySQL server has gone away.
pool_recycle (or the equivalent) to a value shorter than wait_timeout. 3600 seconds (1 hour) is a safe default.
ProxySQL for Multi-Server Setups
Application-level pools work well for a single server. When you have replicas or multiple application servers, a dedicated proxy like ProxySQL sits between the application and MySQL and handles pooling at the infrastructure level. ProxySQL benefits:- Query routing: send reads to replicas, writes to primary
- Connection multiplexing: many application connections share fewer MySQL connections
- Failover: reroute traffic if a server goes down
Tuning max_connections
max_connections sets the server-side ceiling. Each connection consumes memory — a baseline of roughly 200KB for thread stack and static buffers, plus additional memory allocated on demand during query execution (sort buffers, read buffers, tmp tables). Under heavy query load the per-connection cost can reach several MB. Setting max_connections too high wastes memory; too low causes ERROR 1040 (08004): Too many connections.
max_connections = (available RAM for connections) / (memory per connection). Monitor Max_used_connections to understand your actual peak, then set max_connections 20–30% above that.
Frequently Asked Questions
How many connections should my pool have?
Start with the number of CPU cores on the database server, then tune up based on load. A heavily I/O-bound workload can benefit from more connections than CPU cores; a CPU-bound workload can’t. HikariCP’s well-known formulaconnections = (core_count * 2) + effective_spindle_count was designed for spinning disks — it doesn’t apply to SSDs. On modern infrastructure, measure your actual concurrency with Threads_running under peak load and use that as your baseline.
What’s the difference between Threads_connected and Threads_running?
Threads_connected counts all open connections — including idle ones sitting in a pool. Threads_running counts connections actively executing a query right now. The gap between the two is your idle connection count. A large Threads_connected with a small Threads_running is normal for a healthy pool.
Should I use persistent connections in PHP?
Avoid them. PHP has no facility to reset a reused connection — left-open transactions, table locks, temporary tables, and changed session variables carry over to the next request. This can cause deadlocks, data corruption, and hard-to-reproduce bugs. Use a proper connection pool (PDO with pooling, or a proxy like ProxySQL) instead.Troubleshooting
| Problem | Solution |
|---|---|
ERROR 1040 (08004): Too many connections | Increase max_connections, reduce pool size, or add ProxySQL |
MySQL server has gone away | Stale connection — set pool_recycle shorter than wait_timeout |
High Threads_connected but low throughput | Pool is oversized — idle connections consume memory; reduce pool size |
| Connection latency spikes under load | Pool is undersized — requests queue for connections; increase pool size or add a proxy |

