Connection Pool Sizing
Connection pool sizing sets the min, max, and acquire timeout so the pool serves peak concurrency without exhausting the database, and a spike waits rather than opening unbounded connections.
Definition
Connection pool sizing is the configuration of the minimum (keep-alive baseline), maximum (bound on database connections), and acquire timeout (how long a caller waits for a free connection) so that the pool serves the peak concurrency without exceeding the database connection limit and a spike waits rather than opening unbounded connections that crash the database.
Context and scope
Applied in every service that connects to a database, where too few connections starve throughput and too many exhaust the database.
Common misconceptions
- A larger pool is always faster — it is faster up to the database limit; past that, the database spends more time on connection management than on queries and throughput drops
- The pool size should equal the thread count — the pool should match the concurrency that issues queries; a pool larger than the concurrency wastes idle connections
Anti-patterns
- Setting the pool max to the thread count with no acquire timeout, so a spike blocks every thread waiting for a connection
- Sharing one large pool across tenants, so one tenant spike exhausts the pool for everyone
Related concepts
Authoritative source
https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
What it is
Connection pool sizing is the configuration of the minimum (keep-alive baseline), maximum (bound on database connections), and acquire timeout (how long a caller waits for a free connection) so that the pool serves the peak concurrency without exceeding the database connection limit and a spike waits rather than opening unbounded connections that crash the database. Applied in every service that connects to a database, where too few connections starve throughput and too many exhaust the database. Performance is a distribution, not a number: the tail determines user experience, and the mean hides the outliers that cause abandonment.
How it works
Measurement targets percentiles at the workload’s actual concurrency, not a single sequential run. The fast path is kept fast by deferring work that is not on it — lazy initialization, coalescing writes, avoiding allocation in hot loops. Profiling finds the bottleneck; micro-optimization without a profile optimizes the wrong thing. Constant factors matter, but algorithmic complexity dominates as scale grows.
When to optimize and pitfalls
Optimize when a measurement shows a concrete cost — latency budget burn, compute spend, user-visible jank. The pitfall is optimizing for the benchmark rather than the workload: a synthetic test that does not reproduce the production access pattern produces a local maximum that hurts globally. Another is trading memory for speed without accounting for the GC or eviction cost the extra allocation introduces.