Introduction
HikariCP is the default connection pool in Spring Boot, but when all connections are in use and the pool cannot create more (reaching maximumPoolSize), new requests wait up to connectionTimeout milliseconds before receiving HikariPool-1 - Connection is not available, request timed out after 30000ms. This happens when connections are held longer than needed (leaked), when pool size is too small for the workload, or when long-running queries block connections. Unlike other pools, HikariCP is optimized for performance and has specific configuration recommendations that differ from common intuition -- smaller pools often perform better than larger ones.
Symptoms
java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms.
at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:696)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:197)Or leak detection warning:
WARN com.zaxxer.hikari.pool.ProxyLeakTask - Connection leak detection triggered for connection HikariProxyConnection@123456789 on thread http-nio-8080-exec-5
Last packet received 45 seconds ago.Common Causes
- Connection not closed: ResultSet, Statement, or Connection not closed in finally block
- Pool size too small: Default pool size of 10 insufficient for concurrent requests
- Long-running transactions: Connections held during slow queries or external API calls
- connectionTimeout too short: Default 30s not enough during traffic spikes
- maxLifetime shorter than database wait_timeout: Database closes connection before pool recycles
- Connection leak: Code path that gets connection but never returns it
Step-by-Step Fix
Step 1: Configure pool for production
# application.yml
spring:
datasource:
hikari:
maximum-pool-size: 20 # Adjust based on DB capacity
minimum-idle: 5 # Faster startup
connection-timeout: 30000 # 30 seconds to get a connection
idle-timeout: 300000 # 5 minutes - close idle connections
max-lifetime: 1200000 # 20 minutes - recycle connections
leak-detection-threshold: 60000 # 60 seconds - log suspected leaks
connection-test-query: SELECT 1 # For validation (not needed with JDBC4)Step 2: Enable and investigate leak detection
```java @Configuration public class DataSourceConfig {
@Bean public HikariDataSource dataSource(HikariConfig config) { config.setLeakDetectionThreshold(60000); // 60 seconds
HikariDataSource ds = new HikariDataSource(config);
// Log pool stats periodically ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.scheduleAtFixedRate(() -> { HikariPoolMXBean poolBean = ds.getHikariPoolMXBean(); log.info("HikariCP - Active: {}, Idle: {}, Waiting: {}", poolBean.getActiveConnections(), poolBean.getIdleConnections(), poolBean.getThreadsAwaitingConnection()); }, 0, 30, TimeUnit.SECONDS);
return ds; } } ```
Step 3: Fix connection leaks with try-with-resources
```java // WRONG: Connection may leak on exception public User findUser(Long id) throws SQLException { Connection conn = dataSource.getConnection(); PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?"); stmt.setLong(1, id); ResultSet rs = stmt.executeQuery(); // If exception thrown here, connection is leaked! if (rs.next()) { return mapUser(rs); } return null; }
// CORRECT: Try-with-resources guarantees cleanup public User findUser(Long id) throws SQLException { String sql = "SELECT * FROM users WHERE id = ?"; try (Connection conn = dataSource.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setLong(1, id); try (ResultSet rs = stmt.executeQuery()) { if (rs.next()) { return mapUser(rs); } } } return null; } ```
Prevention
- Set leak-detection-threshold to catch connection leaks in development (60s)
- Use JPA/Hibernate which manages connection lifecycle automatically
- Size pool based on expected concurrent database operations, not thread count
- Set max-lifetime below your database server's wait_timeout/interactive_timeout
- Use try-with-resources for all direct JDBC code
- Monitor HikariCP metrics with Micrometer and set alerts on active connections
- Profile slow queries -- a single slow query can block a connection for seconds