A database connection pool is a managed collection of reusable database connections. Instead of opening a new connection for every HTTP request, a Spring Boot application borrows an available connection, runs the database operation, and returns the connection to the pool.
Spring Boot uses HikariCP as its default JDBC connection pool when the application uses Spring JDBC or Spring Data JPA. HikariCP is lightweight, fast, and designed for reliable connection management.
Creating a database connection involves network communication, authentication, session setup, and database-side resources. Recreating a connection for every request adds unnecessary overhead.
A pool creates and reuses connections, which reduces the cost of repeatedly opening and closing database sessions.
Because connections are already available, requests spend less time waiting for database setup. A pool also supports concurrent requests by managing multiple connections safely.
The maximum pool size limits how many connections an application can use at the same time. This prevents a busy application from opening an uncontrolled number of connections and overwhelming the database server.
Idle connections can also be removed after a configured period, allowing unused resources to be released.
HikariCP validates and replaces connections that are closed, expired, or no longer usable. Connection timeouts also prevent requests from waiting forever when the pool has no available connection.
Connection pooling helps an application handle more concurrent requests efficiently. However, pool size must be planned across all application instances so the combined number of connections stays within the database server’s limits.
In a standard Spring Boot application, you usually do not need to add a separate HikariCP dependency. HikariCP is brought in by the Spring Boot JDBC or Spring Data JPA starter and is selected automatically when it is available.
You still need to add the JDBC driver for your database. The following Maven dependencies create a simple Spring Boot REST application that uses JPA with MySQL:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>student</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>student</name>
<description>Spring Boot HikariCP demonstration</description>
<properties><java.version>17</java.version></properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The following example exposes basic student endpoints. When the repository accesses MySQL, the datasource obtains connections from HikariCP automatically.
package com.example.student.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String course;
// Constructors, getters, and setters omitted for brevity
}
package com.example.student.repository;
import com.example.student.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StudentRepository extends JpaRepository<Student, Long> {
}
package com.example.student.service;
import com.example.student.entity.Student;
import com.example.student.repository.StudentRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class StudentService {
private final StudentRepository studentRepository;
public StudentService(StudentRepository studentRepository) {
this.studentRepository = studentRepository;
}
public List<Student> findAll() {
return studentRepository.findAll();
}
public Student save(Student student) {
return studentRepository.save(student);
}
}
package com.example.student.controller;
import com.example.student.entity.Student;
import com.example.student.service.StudentService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/students")
public class StudentController {
private final StudentService studentService;
public StudentController(StudentService studentService) {
this.studentService = studentService;
}
@GetMapping
public List<Student> findAll() {
return studentService.findAll();
}
@PostMapping
public Student create(@RequestBody Student student) {
return studentService.save(student);
}
}
Add the datasource and HikariCP settings to src/main/resources/application.properties:
spring.application.name=student
server.port=9090
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=your-password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
# HikariCP settings
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.pool-name=StudentHikariPool
spring.datasource.hikari.max-lifetime=600000
| Property | Description |
|---|---|
connection-timeout | Maximum time, in milliseconds, that a request waits for a connection. |
maximum-pool-size | Maximum number of connections in the pool. |
minimum-idle | Minimum number of idle connections maintained by the pool. |
idle-timeout | Maximum time an unused connection can remain idle. |
max-lifetime | Maximum lifetime of a connection before HikariCP replaces it. |
pool-name | Name shown in logs and monitoring tools. |
A larger pool does not automatically improve performance. Each active connection consumes memory and database resources. Start with a reasonable value, measure application behavior, and adjust the pool after reviewing metrics.
Consider the database connection limit, the number of application instances, average query duration, and the number of concurrent requests. For example, ten connections per instance across five instances can consume up to fifty database connections.
Temporary debug logging can help verify the configured pool and investigate connection problems:
logging.level.com.zaxxer.hikari.HikariConfig=DEBUG
logging.level.com.zaxxer.hikari=TRACE
Use TRACE logging carefully because it can generate a large amount of output. Disable it or reduce it after troubleshooting.
Spring Boot Actuator can expose datasource metrics such as active connections, idle connections, pending requests, and connection timeouts. Expose only the endpoints required by your environment and protect operational endpoints.
management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=when-authorized
JMeter can simulate concurrent requests and help you observe how the application behaves when many users access the database at the same time.
Download JMeter from the official Apache JMeter website, extract the archive, and start jmeter.bat on Windows or jmeter on Linux and macOS.
Create a Thread Group under a new Test Plan. As a starting example, configure:
Add an HTTP Request sampler for the student endpoint:
localhost9090GET/studentsAdd a Summary Report or View Results in Table listener, start the Spring Boot application, and run the test plan. Review response time, throughput, errors, and connection-pool metrics together. A slow response time does not always indicate a pool problem; queries, database indexes, network latency, and application code can also be responsible.
Configure reliable database connection pooling for Spring Boot applications.