Skip to content
Spring Boot sb databases 3 min read

Connection Pooling (HikariCP)

Opening a database connection is expensive, so applications keep a pool of reusable connections instead of creating one per request. Spring Boot ships HikariCP as the default and only-configured pool, valued for its speed and small footprint. You rarely need to add anything: HikariCP is pulled in transitively by spring-boot-starter-data-jpa and spring-boot-starter-jdbc.

How pooling works

When a request needs the database, it borrows a connection from the pool, runs its query, and returns it. If every connection is in use, the caller waits up to connection-timeout for one to free up. Idle connections beyond the minimum are eventually retired. This recycling avoids the TCP and authentication overhead of opening fresh connections on every query.

Configuration

All HikariCP settings live under spring.datasource.hikari.*. Here is a typical production block.

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/shopdb
    username: shop
    password: secret
    hikari:
      pool-name: shop-pool
      maximum-pool-size: 10
      minimum-idle: 10
      connection-timeout: 30000   # 30s
      idle-timeout: 600000        # 10m
      max-lifetime: 1800000       # 30m
      keepalive-time: 120000      # 2m

Note: Values are in milliseconds. The defaults are sensible for many apps; the most important value to set deliberately is maximum-pool-size.

Key properties

PropertyDefaultMeaning
maximum-pool-size10Hard cap on total connections (active + idle)
minimum-idle= max-pool-sizeMinimum idle connections kept ready
connection-timeout30000Max ms to wait for a connection before throwing
idle-timeout600000Ms an idle connection may sit before retirement
max-lifetime1800000Max age of a connection before it is replaced
keepalive-time0 (off)Interval to ping idle connections to keep them alive
auto-committrueWhether borrowed connections start in auto-commit

Tip: HikariCP’s author recommends a fixed-size pool: set minimum-idle equal to maximum-pool-size. A fixed pool has more predictable latency than one that grows and shrinks under load.

Sizing the pool

Bigger is not better. Each connection consumes resources on the database server, and too many connections cause contention. A widely used starting formula is:

pool size = (core_count * 2) + effective_spindle_count

For a modern app on SSD-backed cloud databases, that often lands around 10. Key guidance:

  • Keep maximum-pool-size well under the database’s max_connections limit, especially when multiple instances connect.
  • If you run N application instances, total connections = N × maximum-pool-size. Budget accordingly.
  • Set max-lifetime a few seconds shorter than any database or load-balancer connection timeout so Hikari retires connections before the server kills them.

Warning: A pool larger than the database can handle leads to slower throughput, not faster. When in doubt, start small (10) and increase only if monitoring shows sustained pool exhaustion.

Diagnosing pool exhaustion

When all connections are checked out and a borrower waits past connection-timeout, Hikari throws:

java.sql.SQLTransientConnectionException: shop-pool - Connection is not available,
request timed out after 30000ms.

This almost always means connections are being held too long (long transactions, missing @Transactional boundaries, or leaks), not that the pool is too small. Investigate query duration before bumping maximum-pool-size.

Monitoring

HikariCP exposes pool metrics through Micrometer when Spring Boot Actuator is on the classpath. Enable metrics and they appear automatically.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Useful gauges include:

MetricMeaning
hikaricp.connections.activeConnections currently in use
hikaricp.connections.idleConnections available
hikaricp.connections.pendingThreads waiting for a connection
hikaricp.connections.timeoutCount of borrow timeouts
hikaricp.connections.usageTime a connection is held before return

A persistently high pending count or any timeout increments are the clearest signals that the pool is undersized or connections are leaking.

management:
  endpoints:
    web:
      exposure:
        include: health, metrics
  endpoint:
    health:
      show-details: when-authorized

Best Practices

  • Use a fixed-size pool (minimum-idle = maximum-pool-size) for predictable latency.
  • Keep total connections across all instances under the database’s connection limit.
  • Set max-lifetime shorter than the database’s idle-connection timeout.
  • Monitor pending and timeout metrics via Actuator rather than guessing.
  • Fix long-held connections (large transactions, N+1 queries) before enlarging the pool.
Last updated June 13, 2026
Was this helpful?