DEV Community

Cover image for Mastering Database Connection Pooling: HikariCP Tuning for High-Throughput APIs
DEVANSHU PATIL
DEVANSHU PATIL

Posted on AI-assisted

Mastering Database Connection Pooling: HikariCP Tuning for High-Throughput APIs

Mastering Database Connection Pooling: HikariCP Tuning for High-Throughput APIs

When an API starts throwing connection timeout exceptions during traffic spikes, the initial reaction of many developers is simple: "Increase the maximum pool size!"

They bump maximumPoolSize from 20 to 100, then to 200. Suddenly, database CPU usage spikes to 100%, disk I/O thrashes, and response times degrade from 15ms to 3 seconds.

Why does adding database connections hurt performance?

In this article, we explore the physics of database connection pooling, examine why small pools outperform large pools, and learn how to tune HikariCP (the default connection pool in Spring Boot) for peak throughput.

The Fundamental Pool Formula: Less Is More

A database server is governed by hardware limits: the number of physical CPU cores, disk I/O throughput, and network interface capacity.

When 200 connections simultaneously execute queries on an 8-core CPU server:

  • Only 8 queries can actually run at any given nanosecond.
  • The remaining 192 connections are actively competing for CPU time.
  • The OS kernel spends more time context switching between threads and thrashing CPU cache lines than executing actual SQL statements!

PostgreSQL and HikariCP engineers established the famous empirical rule for pool sizing:

$$\text{Connections} = (\text{Core Count} \times 2) + \text{Effective Spindle Count}$$

For a modern server with 8 CPU cores and fast NVMe SSD storage:
$$\text{Connections} = (8 \times 2) + 1 = 17 \text{ connections!}$$

A pool of 15 to 25 connections will routinely achieve higher transactions-per-second than a pool of 200 connections on the same hardware.

Critical HikariCP Configuration Parameters

Here is an optimized production configuration in application.yml:

spring:
  datasource:
    hikari:
      pool-name: ProductionHikariCP
      maximum-pool-size: 20
      minimum-idle: 20
      connection-timeout: 30000     # 30 seconds
      idle-timeout: 600000          # 10 minutes
      max-lifetime: 1800000         # 30 minutes
      leak-detection-threshold: 2000 # 2 seconds
      auto-commit: true
Enter fullscreen mode Exit fullscreen mode

Key Settings:

  1. Fixed Pool Size (maximum-pool-size == minimum-idle): Prevents runtime latency spikes from dynamically establishing new TCP handshakes during traffic surges.
  2. max-lifetime (30 mins): Retires connections gracefully before cloud NAT gateways or firewalls drop stale TCP connections.
  3. leak-detection-threshold (2000ms): Logs a stack trace warning whenever a thread holds a connection for longer than 2 seconds, immediately identifying unclosed connections.

Key Production Takeaways

  1. Keep pools small: Measure query throughput while gradually lowering your pool size. You will often find lower latency and higher QPS with 20 connections than 100.
  2. Never perform external I/O inside @Transactional: Never invoke external REST APIs or write to disk while holding a database connection. Check out the connection as late as possible and return it immediately.
  3. Turn on Leak Detection: Set leak-detection-threshold = 2000 in staging and production to catch connection retention bugs early.

Top comments (0)