Connection Pool — HikariCP
IntermediateSpring Boot auto-configures HikariCP as the default connection pool; tuning maximumPoolSize, connectionTimeout, and keepaliveTime is critical for production.
Overview
HikariCP is Spring Boot's default JDBC connection pool — chosen for its low overhead (~50 μs acquire time) and small footprint. A connection pool maintains a set of pre-established DB connections and lends them to application threads on demand, avoiding the cost of TCP handshake + TLS + DB authentication on every query. The most critical tuning decision is `maximumPoolSize`: set it too low and requests queue up; set it too high and you overwhelm the DB (each PostgreSQL connection consumes ~5–10 MB). The Hikari team's rule of thumb: `pool_size = (number_of_cores * 2) + effective_spindle_count`, typically 10–20 for most services. `connectionTimeout`, `idleTimeout`, `maxLifetime`, and `keepaliveTime` handle stale connections.
Key Configuration Properties
`maximumPoolSize` is the most important parameter — it caps the total concurrent DB connections. `minimumIdle` controls how many connections are kept warm when the pool is idle (set equal to `maximumPoolSize` to disable dynamic sizing and avoid cold-start latency). `connectionTimeout` is how long a thread waits for a connection from the pool before throwing `SQLTimeoutException`.
# application.properties — HikariCP tuning
spring.datasource.hikari.maximum-pool-size=20 # max concurrent connections
spring.datasource.hikari.minimum-idle=20 # keep pool warm (= max for fixed pool)
spring.datasource.hikari.connection-timeout=30000 # 30s wait for connection from pool
spring.datasource.hikari.idle-timeout=600000 # 10min: release idle connections
spring.datasource.hikari.max-lifetime=1800000 # 30min: max connection age (rotate before DB server times out)
spring.datasource.hikari.keepalive-time=60000 # 1min: ping idle connections to prevent firewall drops
spring.datasource.hikari.pool-name=OrderDB-Pool # name shown in JMX/logs
# Validate configuration at startup
spring.datasource.hikari.initialization-fail-timeout=1 # fail fast if DB unreachableSizing the Pool and Diagnosing Exhaustion
Pool exhaustion (all connections in use) causes request threads to queue at `connectionTimeout`. Symptoms: slow responses, `SQLTimeoutException` errors, high `hikaricp_pending_threads` metric. Root causes: too-low `maximumPoolSize`, slow queries holding connections too long, N+1 queries, or missing indexes. Diagnose with the HikariCP Prometheus metrics exposed by Micrometer.
# Prometheus metrics via Micrometer (spring-boot-actuator + micrometer-registry-prometheus)
hikaricp_connections_active # currently in use
hikaricp_connections_idle # available
hikaricp_connections_pending # threads waiting → alert if > 0 for > 5s
hikaricp_connections_timeout_total # total exhaustion events since start
hikaricp_connections_max # maximumPoolSize
# Grafana alert rule
- alert: HikariPoolExhaustion
expr: hikaricp_connections_pending{pool="OrderDB-Pool"} > 0
for: 10s
annotations:
summary: "HikariCP pool exhausted — increase maximumPoolSize or optimise queries"
# Formula for maximumPoolSize (Hikari team recommendation):
# pool_size = (core_count * 2) + effective_spindle_count
# e.g. 4 cores, 1 SSD → (4 * 2) + 1 = 9, round up to 10Connection Validation and Stale Connections
Connections can go stale when a firewall or the DB server closes them while they are idle in the pool. `keepaliveTime` pings idle connections; `maxLifetime` forces rotation before the DB server's `wait_timeout` closes them. Always set `maxLifetime` to slightly less than the DB server's connection timeout. `connectionTestQuery` (or the JDBC4 `isValid()`) validates connections on acquisition.
# Prevent stale connections
spring.datasource.hikari.max-lifetime=1800000 # 30min (< MySQL wait_timeout of 8h default)
spring.datasource.hikari.keepalive-time=60000 # ping every 60s when idle
# For MySQL: ensure maxLifetime < wait_timeout
# Check: SHOW VARIABLES LIKE 'wait_timeout'; (default: 28800 = 8h)
# Set: spring.datasource.hikari.max-lifetime=1740000 (29min < 30min wait_timeout if custom)
# JDBC4+ (Postgres, MySQL 5.6+): isValid() used automatically — no connectionTestQuery needed
# For older JDBC3 drivers:
spring.datasource.hikari.connection-test-query=SELECT 1
# Multiple DataSources (e.g. primary + read-replica)
@Bean
@Primary
@ConfigurationProperties("spring.datasource.primary.hikari")
HikariDataSource primaryDataSource() { ... }
@Bean
@ConfigurationProperties("spring.datasource.replica.hikari")
HikariDataSource replicaDataSource() { ... }Key Points to Remember
- 1HikariCP is Spring Boot's default pool — ~50 μs acquire time, minimal overhead
- 2maximumPoolSize is the most critical tuning knob — too low queues requests, too high overwhelms the DB
- 3Set minimumIdle = maximumPoolSize for a fixed pool with no cold-start latency
- 4maxLifetime must be less than the DB server's wait_timeout to prevent stale connections
- 5keepaliveTime pings idle connections to prevent firewall/NAT dropping them
- 6Monitor hikaricp_connections_pending — non-zero means pool exhaustion; tune size or fix slow queries
Interview Questions
Sign in to ask AriaWhat happens when all HikariCP connections are in use and a new request arrives?
How would you size the maximumPoolSize for a service running on 4-core nodes?
What is a stale connection and how does maxLifetime prevent it?
What is the difference between connectionTimeout and maxLifetime in HikariCP?
How would you detect and alert on HikariCP pool exhaustion in production?
Ask Aria about Connection Pool — HikariCP
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.