Connection Pooling
This note is complete, reviewed, and considered stable.
A database connection is a persistent communication channel between an application and a database server.
Establishing a connection involves:
- TCP handshake
- Authentication (credentials, certificates, SSL)
- Allocating memory and worker resources on the database
- Registering a session in the database’s internal state
This makes connection creation significantly more expensive than executing most queries.
Naive ways to connect to a database (and why they fail)
One connection per request
Request arrives
→ Open database connection
→ Execute query
→ Close connection
→ Send response
Why this approach fails
- Connection setup dominates request latency
- High CPU and memory usage on the database
- Connection storms during traffic spikes
- Poor scalability beyond low traffic
This model is acceptable only for scripts or extremely low-load systems.
Single shared global connection
Create one DB connection
Reuse it for all requests
Why this approach fails
- No real concurrency
- Thread safety issues
- One broken connection breaks the entire system
Core idea of connection pooling
Connection pooling means:
Maintain a fixed number of pre-opened database connections and reuse them across requests.
Connections are borrowed, not created or destroyed per request.
How connection pooling works internally
Pool initialization
At application startup:
- Connections are created once
- Stored in an idle state
- Kept alive for reuse
Request lifecycle with pooling
Key rule:
- Connections must always be returned to the pool
Pool exhaustion and waiting
When all connections are busy:
This introduces backpressure, protecting the database.
Key characteristics of a connection pool
Pool size
The pool enforces a maximum number of concurrent database connections.
- Small pool → higher wait times
- Large pool → database overload
The pool size is a control knob, not a performance booster.
Connection reuse
The same connection serves many requests over time, amortizing setup costs.
Advantages of connection pooling over other approaches
Performance advantage
Compared to per-request connections:
Pooling removes repeated connection overhead from the critical path.
Scalability advantage
- Application concurrency ≠ database concurrency
- Pool acts as a gatekeeper
Database protection
From the database’s perspective:
The pool:
- Prevents connection floods
- Keeps resource usage stable
- Improves predictability under load
Resource efficiency
Without pooling:
- Constant connection creation/destruction
- High CPU and memory churn
With pooling:
- Long-lived connections
- Better cache and worker reuse
Fault tolerance
Pools can:
- Detect broken connections
- Replace them automatically
- Retry safely
This logic is centralized instead of duplicated across application code.
Connection pooling vs concurrency (important distinction)
- Many threads can exist
- Only limited DB access is allowed
- Excess work waits instead of crashing the database
This is intentional system design, not a bottleneck.
Common production failure modes
Connection leaks
Result:
- Requests hang
- System degrades over time
Oversized pools
More connections increase contention and reduce performance.
Long-running transactions
Connections held too long reduce pool availability and cause cascading delays.
Real-world implementations
Connection pooling is built into most ecosystems:
- Java → HikariCP
- Python → SQLAlchemy / Django
- Go →
database/sql - Node.js → driver-level pools
Different APIs, same underlying model.