Quick answer
Database connection pooling keeps a reusable set of database connections open so backend requests do not create a new connection for every query.
A connection pool improves latency and protects the database from uncontrolled connection growth, but it must be sized carefully. Too few connections create waiting. Too many connections can overload the database.
The most important settings are maximum pool size, connection timeout, idle timeout, max lifetime, leak detection, and monitoring.
Why connection pools exist
Opening a database connection is not free. A new connection may require network setup, authentication, TLS negotiation, memory on the database server, session state, and driver initialization.
If every request opened and closed a physical connection, a busy API would waste time and resources before it even runs SQL.
A pool changes the workflow:
request -> borrow connection -> run query -> return connection to pool
The physical connection stays open and can be reused by another request.
The basic pool lifecycle
Most backend connection pools follow the same lifecycle:
- Start with a small number of idle connections or create them on demand.
- A request borrows a connection.
- The request runs queries and transactions.
- The request closes the logical connection handle.
- The pool returns the physical connection to the idle set.
- Old, broken, or expired connections are replaced.
The application code usually calls close(), but that does not necessarily close the real database socket. It returns the connection to the pool.
Pool size is a capacity decision
Pool size controls how many concurrent database connections one application instance can use.
For example:
10 app instances
20 max connections per instance
= up to 200 database connections
If the database can safely handle 150 application connections, this configuration is too high even though each individual service instance looks reasonable.
Pool sizing must account for:
- Number of application instances.
- Database max connections.
- Other services using the same database.
- Admin tools, migration jobs, workers, and reporting jobs.
- Average query latency and transaction duration.
- Traffic spikes and retry behavior.
Bigger is not always better
A larger pool can reduce waiting inside the application, but it can also make the database slower.
Databases have finite CPU, memory, locks, buffers, and I/O. If too many queries run at once, they compete with each other. Latency rises, requests hold connections longer, and the system can enter a feedback loop.
Sometimes a smaller pool improves stability because it limits concurrency before the database is saturated. The queue moves to the application, where timeouts and backpressure are easier to control.
Connection timeout
Connection timeout controls how long a request waits to borrow a connection from the pool.
If the pool is exhausted, the request waits. If no connection becomes available before the timeout, the application returns an error.
A good timeout should be short enough to fail quickly during overload and long enough to tolerate normal short bursts.
Symptoms of pool exhaustion include:
- Requests waiting before SQL starts.
- Timeout errors from the pool, not the database.
- High active connection count.
- Low idle connection count.
- Long transactions or leaked connections.
Idle timeout and max lifetime
Idle timeout removes connections that have been unused for a while. This prevents idle application instances from holding unnecessary database resources.
Max lifetime retires old connections even if they are otherwise healthy. This helps avoid stale connections behind load balancers, database restarts, network changes, and server-side connection limits.
These values should be coordinated with database and infrastructure settings. If the database or proxy closes connections earlier than the pool expects, the application may see sudden broken-connection errors.
Connection leaks
A connection leak happens when application code borrows a connection and does not return it.
Common causes include:
- Missing
close()in manual JDBC code. - Exceptions that skip cleanup.
- Transactions that never complete.
- Streaming results held open too long.
- Background jobs that keep a connection while doing non-database work.
Modern frameworks reduce this risk, but leaks still happen when code mixes manual connection management, custom transactions, and long-running jobs.
Leak detection can log a warning when a connection has been checked out too long.
Transactions and pool pressure
A request holds a connection for the duration of its transaction.
This is why long transactions can exhaust a pool even if the SQL itself is not expensive. If application code opens a transaction, calls an external API, waits for a remote service, and then commits, the database connection is held for the whole wait.
Read Database Transactions Explained for transaction boundaries and why external calls should usually happen outside active database transactions.
Pools and background workers
Background workers need pool sizing too.
A queue worker fleet can create more database load than HTTP traffic because workers often run batch updates, retries, imports, exports, or scheduled maintenance.
Do not only count web server instances. Count:
- API servers.
- Worker processes.
- Scheduled jobs.
- Migration tasks.
- Local admin scripts.
- Reporting services.
Each process may have its own pool.
Monitoring connection pools
Useful pool metrics include:
| Metric | Why it matters |
|---|---|
| Active connections | How many connections are currently borrowed. |
| Idle connections | How much room is available without creating new connections. |
| Pending waiters | How many requests are waiting for a connection. |
| Borrow wait time | Whether requests are delayed before SQL starts. |
| Timeout count | Whether the pool is rejecting work. |
| Connection lifetime | Whether connections churn too often. |
| Leak warnings | Whether code holds connections too long. |
Pool metrics should be viewed next to database CPU, query latency, lock waits, and request latency.
Common mistakes
The first mistake is setting the pool size per instance without multiplying by the number of instances.
The second mistake is increasing pool size every time latency rises. If the database is already saturated, more connections can make latency worse.
The third mistake is running slow external calls inside transactions. That keeps a database connection busy while no database work is happening.
The fourth mistake is ignoring workers and migration jobs. Production connection limits are shared by everything that connects to the database.
The fifth mistake is using long timeouts that turn overload into a slow queue instead of a clear failure.
Practical backend checklist
When configuring a database pool:
- Count all application instances and workers.
- Check the database’s safe connection limit.
- Reserve connections for admin, migration, and emergency access.
- Start with a conservative max pool size.
- Set a clear connection timeout.
- Enable pool metrics.
- Enable leak detection in non-production and for suspicious production services.
- Keep transactions short.
- Load test realistic request and worker concurrency.
- Review pool settings whenever autoscaling changes.
Connection pooling is part of system design because it controls the pressure between application concurrency and database capacity.
For a Spring service, Spring Service Layers and Transaction Boundaries Explained shows how remote waits and propagation choices retain borrowed connections, and Spring Data JPA Query Performance Explained connects acquisition delay to the SQL and locks behind it. During active customer impact, Production Spring Boot Incident Troubleshooting prevents pool size from becoming an untested first response.
When pool pressure becomes user impact, RED, USE, and Golden Signals connects request duration to utilization and waiters, and the Production Incident Troubleshooting runbook carries that evidence through mitigation and recovery.
When unrelated workloads contend for the same connections, Bulkhead Pattern and Resource Isolation shows how bounded pool partitions preserve critical capacity. During active saturation, Production Overload Troubleshooting connects pool wait to admission, retries, queues, and verified user recovery.
Related reading
Read Database Read Replicas Explained for separate writer/reader pool design and Database Transactions Explained for transaction boundaries. Database Indexes Explained covers query performance after a connection is borrowed, while N+1 Query Problem Explained covers many small queries consuming the pool.
When borrowed connections remain occupied, Database Lock Contention and Long Transactions shows how to reconstruct the blocker chain without confusing pool wait with statement execution; Production Slow Query Troubleshooting then connects that evidence to user impact, safe mitigation, and recovery validation.
This production update follows the Spring order service across both supported database engines.
Learning objectives
- Budget all Spring pools against finite database sessions and work capacity.
- Separate acquisition wait from query, transaction, lock, and network time.
Prerequisites
Know JDBC, transactions, timeouts, replicas, and application concurrency.
Shared relational contract
A pool reuses sessions and bounds admission; it cannot manufacture CPU, I/O, locks, or useful commits. Use the course and topic.
PostgreSQL 18 boundary
PostgreSQL backend processes, session limits, activity, wait events, and transaction state define its evidence.
MySQL 8.4 InnoDB boundary
MySQL threads, connection limits, Performance Schema, and InnoDB transaction waits define 8.4 evidence.
Production failure scenario
When pool wait rises, inspect long transactions, locks, leaks, demand, and all replica pools before resizing.
Common misconceptions
More connections or application replicas can amplify contention instead of adding capacity.
Decision checklist
Budget globally, reserve headroom, bound acquisition, detect leaks, and verify useful completions.
Official sources
PostgreSQL monitoring and MySQL connection interfaces, accessed August 19, 2026. See lock contention and production resilience.