Database Connection Pooling Explained
Fast recall
Quick revision
Core answer
Understanding of the cost of connection creation and the operational risks of too many or too few database connections in a production system.
Setting the pool size too large -- PostgreSQL forks a process per connection, so hundreds of connections create memory and context-switching overhead. The optimal pool size is often much smaller than expected.
Explain the formula for optimal pool size: (core count * 2) + effective_spindle_count, and discuss HikariCP configuration tuning -- idle timeout, max lifetime, connection timeout.
Interview-ready guide
Interview answer
Connection pooling exists because creating a database connection is expensive — not just "a bit slow," but 10–50ms per connection for TCP handshake, authentication, and session setup. At any meaningful request volume, that cost dominates.
What pooling does
- A pool pre-creates a fixed number of authenticated connections and keeps them ready — when a request needs the database, it borrows one from the pool, uses it, and returns it, so the connection overhead happens once at startup, not on every request
- Without pooling on a service handling 1,000 req/sec, you'd need 1,000 concurrent connections — PostgreSQL forks a backend process per connection, so that's 1,000 processes consuming memory even when most are idle
Sizing the pool — smaller than you think
- The common mistake is setting pool size to match thread count or request volume — but the bottleneck isn't connection slots, it's the database CPU and disk
- HikariCP's guidance:
pool size = (CPU cores x 2) + effective spindle count— for a 4-core database server, roughly 9-10 connections outperform 200 because the database can only execute that many queries in parallel - A pool that's too large means hundreds of connections queuing at the database level, consuming memory without gaining throughput
Key HikariCP settings
maximumPoolSize: the ceiling — start conservative and raise based on observed pool wait time, not instinctconnectionTimeout: how long a thread waits for a pool connection before throwing; the default 30 seconds is too long for production — set 5-10 seconds so callers fail fast rather than hangingmaxLifetime: rotate connections periodically so a database failover or firewall timeout doesn't leave broken connections that only fail at query time
In Spring Boot, HikariCP is the default pool. The most important metric to monitor is pool wait time: if threads are consistently waiting for a connection, either the pool is too small or queries are holding connections too long.
Database Connection Pooling Explained
Direct Answer
Connection pooling maintains a pre-created set of database connections that are reused across requests, rather than opening and closing a connection for every query. It matters because establishing a TCP connection plus a database authentication handshake takes 10-50ms -- far longer than most queries. Pooling eliminates that overhead and limits the total connections to the database, preventing resource exhaustion.
Code Example
// HikariCP configuration via application.properties (Spring Boot)
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=app
spring.datasource.password=secret
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.keepalive-time=60000
// Java config equivalent
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb");
config.setUsername("app");
config.setPassword("secret");
// Formula: (cpu_cores * 2) + disk_spindles -- often 10-20
config.setMaximumPoolSize(10);
config.setMinimumIdle(5);
config.setConnectionTimeout(30_000); // max wait for a connection from pool
config.setMaxLifetime(1_800_000); // rotate before DB enforces idle timeout
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
return new HikariDataSource(config);
}
// Micrometer metrics registered automatically by HikariCP:
// hikaricp.connections.active
// hikaricp.connections.idle
// hikaricp.connections.pending <-- alert when consistently > 0
Common Mistakes & Pitfalls
Setting the pool size too large -- PostgreSQL forks a process per connection, so hundreds of connections create memory and context-switching overhead. The optimal pool size is often much smaller than expected.
Check your understanding
Answer these without looking back at the article.
- What is PgBouncer and when would you use it alongside HikariCP?
- How do you tune HikariCP pool size for a Kubernetes deployment with auto-scaling?
- What happens to pooled connections when the database restarts?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.