Spring Boot Connection Pooling with HikariCP

Configure HikariCP in Spring Boot, budget connections across replicas, distinguish pool and query timeouts, and diagnose exhausted pools and connection leaks.

Last reviewed: November 2026

·Spring Boot 2.7Spring Boot 3.xHikariCP
✅
Quick Understanding: A JDBC connection pool reuses database connections. Application code borrows a connection for database work and returns it when the operation or transaction finishes. With standard JDBC or JPA starters, Spring Boot normally uses HikariCP when it is available; every application replica has its own pool.

🔍 What Is It?

Opening a physical database connection for every query adds authentication and network setup work. A pool keeps reusable connections and limits how many can be used concurrently.

Spring Boot prefers HikariCP for an auto-configured JDBC DataSource when HikariCP is on the classpath. This is not a rule for every application: a custom DataSource, another selected pool, or a reactive R2DBC connection factory changes the configuration path.

Connections are not request threads

An HTTP request may need no database connection, one connection for part of its lifetime, or a connection held across a transaction. Increasing server threads does not create additional database capacity. A larger pool can increase database contention rather than improve throughput.

Core HikariCP settings

Property under spring.datasource.hikariPurposeImportant distinction
maximum-pool-sizeMaximum connections in this poolApplies per DataSource and replica
minimum-idleTarget idle connections to maintainOmitting it normally gives fixed-size behavior relative to maximumPoolSize
connection-timeoutHow long a borrower waits for a connection, in millisecondsDoes not limit query execution time
validation-timeoutConnection validation timeout, in millisecondsMust be below connectionTimeout
idle-timeoutRetirement of excess idle connectionsMatters when minimumIdle is below maximumPoolSize
max-lifetimeMaximum connection lifetimeAn in-use connection is not forcibly interrupted at this age
leak-detection-thresholdLogs a diagnostic for long checkoutsA warning does not prove a leak

Use the property names and limits supported by the HikariCP version managed by your Spring Boot release.

🎯 Why Do We Need It?

A bounded pool provides a reusable connection budget. It protects database capacity only when all application instances, other services, migrations, monitoring, and administrative connections are considered together.

Pool configuration also creates a clear failure boundary: when borrowers wait longer than connectionTimeout, acquisition fails instead of waiting indefinitely. That failure needs an application-level response and telemetry; it does not automatically resolve database overload.

🏗️ What Happens in Real Projects?

Consider a database limited to 100 connections. If the peak deployment has six replicas, each with a maximum pool of 10, the application's potential demand is 60 connections. Allowing 20 for other clients and 20 for operational headroom uses the full budget.

Include rolling-deployment overlap and autoscaling in the peak replica count. Seven replicas under the same assumptions would require 110 connections, exceeding that budget. Multiple DataSources in one replica also need separate accounting.

This calculation is a capacity constraint, not proof that a pool of 10 is optimal. Measure database work concurrency, throughput, query latency, and connection acquisition delay under representative load.

⚙️ How It Works

  1. A JDBC client requests a connection from the DataSource.
  2. HikariCP supplies an available connection or waits for capacity within connectionTimeout.
  3. SQL work runs. A transaction can retain the connection until transaction completion.
  4. Application code closes a manually borrowed connection, or the framework releases it. Closing the pool's proxy normally returns the connection for reuse rather than closing the physical connection immediately.
  5. The pool validates, replaces, or retires connections according to configuration and connection health.

Timeouts solve different problems

A connection acquisition timeout limits waiting to borrow. A statement/query timeout limits SQL work through the relevant JDBC, JPA, or database mechanism. Socket timeouts constrain driver/network operations. A transaction timeout has its own framework semantics. Setting connectionTimeout alone does not bound the other stages.

Set maxLifetime below known database or infrastructure connection lifetime limits, with a margin. Do not assume the illustrative value below matches a managed database's policy.

💻 Example

HikariCP Configuration and Connection Ownership — Illustrative JDBC properties plus a Spring service that returns a manually borrowed connection.

properties
# Requires a JDBC/JPA starter and the matching database driver.
# Keep connection details in the deployment environment.
spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}

# Example values, not universal production recommendations.
spring.datasource.hikari.pool-name=application-pool
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=2
spring.datasource.hikari.connection-timeout=3000
spring.datasource.hikari.validation-timeout=1000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1500000

# Optional temporary diagnostic; legitimate long work can also trigger it.
# spring.datasource.hikari.leak-detection-threshold=30000

🤔 Common Confusions

❓ Does connectionTimeout stop a slow SQL query?

No. It limits the wait to borrow a connection. Query execution, transaction, and driver socket timeouts are separate controls.

❓ Is a full pool always a connection leak?

No. Legitimate concurrency, long transactions, locks, or slow queries can keep every connection busy. Correlate checkouts and database activity before concluding that application code forgot to release a connection.

❓ Does closing a pooled connection close the database socket?

Closing the proxy normally returns the connection to the pool. The pool owns physical connection retirement. A broken or retired connection can be physically closed rather than reused.

🚨 Common Production Issues

Pool exhausted with pending borrowers — investigate query duration, lock waits, transaction length, and concurrency before changing the maximum.

Autoscaling exceeds the database connection limit — include every replica, rolling overlap, DataSource, and other client in the capacity budget.

Remote calls inside long transactions hold scarce connections while no SQL is executing — reduce transaction scope where correctness permits.

Connection creation or validation fails because infrastructure has closed a connection — check driver errors and align lifetimes with the actual database/network policy.

Manual JDBC checkout is not closed on an error path — use try-with-resources or framework-managed data access with clear ownership.

✅ Best Practices

Measure acquisition latency and active, idle, and pending connections alongside query latency and database utilization.

Use a connection budget based on peak instances rather than configuring each replica in isolation.

Keep transactions focused on the database unit of work and avoid unrelated blocking operations inside them.

Treat maximum pool size as a measured concurrency limit rather than equating it to the number of HTTP threads.

Configure acquisition, validation, query, socket, and transaction timeouts according to their separate responsibilities.

Use long-checkout diagnostics as evidence to investigate, not as a mechanism that repairs or forcibly reclaims leaks.

🏛️ Architect's Note

Senior Architect's Perspective

Pooling coordinates a finite database resource across many callers. Begin with a total connection budget, then measure how long each unit of work holds a connection and how the database behaves at that concurrency. Increasing capacity without shortening slow transactions or resolving locks can move the bottleneck into the database and worsen latency.

💬 Frequently Asked Questions

Does Spring Boot use HikariCP by default?

For auto-configured JDBC access, Spring Boot prefers HikariCP when it is available, which is normally the case with the standard JDBC or JPA starters. A custom DataSource, an explicitly selected pool, or R2DBC changes that assumption.

What should maximum-pool-size be?

There is no universal value. Bound the sum of peak replica pools by database capacity after other clients and headroom, then measure throughput, acquisition delay, and database contention under realistic load.

What is the difference between connection-timeout and max-lifetime?

connection-timeout limits how long a borrower waits for a connection. max-lifetime limits connection age for retirement. HikariCP does not forcibly interrupt an in-use connection simply because it reaches max-lifetime; it retires it when returned.

Should minimum-idle equal maximum-pool-size?

HikariCP normally uses maximumPoolSize as the default minimumIdle, giving fixed-size behavior. A smaller configured minimum can reduce idle connections but changes how the pool replenishes capacity. Choose deliberately for the workload rather than assuming one setting is always better.

Why do I get connection is not available, request timed out?

The pool could not provide a connection within its acquisition timeout. Check connection-creation errors, long queries, locks, transaction duration, request concurrency, and connection ownership. The message alone does not identify a leak or prove that the pool is too small.

Does leak detection fix leaked connections?

No. It logs when a checkout exceeds the configured threshold. Legitimate long work can trigger it too. Use the checkout trace and transaction evidence to find the cause and correct ownership or execution time.

How does autoscaling change pool sizing?

Each replica can create its own maximum number of connections. Include scaling peaks and deployment overlap, plus other applications and administrative clients. A safe per-instance pool can exceed the database limit when multiplied across instances.

🎯 Key Takeaways

1A pooled connection is borrowed and returned; ownership still matters.
2Spring Boot normally selects HikariCP for auto-configured JDBC when available.
3Pool size is a per-DataSource, per-instance limit within a database-wide budget.
4Acquisition timeouts do not stop slow queries.
5Diagnose exhaustion with database activity and transaction duration, not the exception alone.
6A larger pool is useful only when the database and measured workload support the extra concurrency.

🎯 Practice this topic in interviews

↗ Where this topic fits

Sources

Sources / References

Use these Spring Boot references to verify the concept in official docs and continue into the most relevant SplashRide pages.

Related SplashRide pages

SplashRide Spring Boot learning path

Browse the full Spring Boot topic collection and learning order on SplashRide.

Spring Boot Interview Prep

Practice Spring Boot interview questions and scenario-based answers.

Backend Engineer Career Path

A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.

Full Stack Java Developer Career Path

A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.

Transactions

Master Spring transaction management — @Transactional, propagation, isolation levels, rollback rules, and the common pitfalls that cause silent data corruption in production.

Database Bottlenecks

Learn how Spring Boot services reveal DB bottlenecks through slow queries, pool pressure, locking, and transaction scope.