Перейти к содержимому
Skip to content
← All articles

Database Connection Pooling: How It Works and Best Practices

Why Connection Pooling Matters

Every database query requires a connection. Creating a new connection involves a TCP handshake, authentication, memory allocation on the database server, and session initialization. For MySQL, this process takes 5–50ms. For PostgreSQL, it can take 50–100ms due to process forking. Multiply this by thousands of requests per second, and connection overhead becomes a major bottleneck.

Connection pooling solves this by maintaining a set of pre-established connections that are shared across requests. Instead of creating and destroying connections, your application borrows a connection from the pool, uses it, and returns it. The result: dramatically lower latency, higher throughput, and reduced load on the database server.

How Connection Pools Work

A connection pool is a cache of database connections. The core lifecycle:

Pool Size Configuration

The most critical setting. Too small: requests queue waiting for connections, increasing latency. Too large: the database is overwhelmed by concurrent connections, each consuming memory and CPU.

ParameterDescriptionTypical Default
min_pool_sizeConnections created at startup5–10
max_pool_sizeMaximum concurrent connections20–50
idle_timeoutClose idle connections after this duration300s
connection_timeoutMax wait time to borrow a connection5–30s
max_lifetimeClose connections after this total age1800s

The Optimal Pool Size Formula

A widely cited formula from the PostgreSQL wiki:

pool_size = (core_count * 2) + effective_spindle_count

Example for a 4-core server with SSD:
pool_size = (4 * 2) + 1 = 9

This is a starting point, not a final answer. The right pool size depends on query duration, concurrency patterns, and whether the workload is CPU-bound or I/O-bound. Profile under realistic load to find the optimum.

A common mistake is setting the pool too large. PostgreSQL performance degrades significantly beyond ~100 connections due to lock contention and context switching. MySQL handles more connections but still suffers beyond 200–300.

Connection Pooling in PHP

PHP's request lifecycle creates a unique challenge: each request typically creates a new database connection and destroys it at the end. Native PHP does not have built-in connection pooling. Solutions include:

// PHP PDO persistent connection
$pdo = new PDO(
    'mysql:host=localhost;dbname=myapp',
    'user',
    'password',
    [PDO::ATTR_PERSISTENT => true]
);

// With ProxySQL, connect to proxy instead of MySQL directly
$pdo = new PDO(
    'mysql:host=127.0.0.1;port=6033;dbname=myapp',
    'user',
    'password'
);

Connection Pooling with PgBouncer

PgBouncer is the most popular connection pooler for PostgreSQL. It sits between the application and PostgreSQL, managing a pool of server connections:

# /etc/pgbouncer/pgbouncer.ini
[databases]
myapp = host=127.0.0.1 port=5432 dbname=myapp

[pgbouncer]
listen_port = 6432
listen_addr = 127.0.0.1
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 25
min_pool_size = 5
reserve_pool_size = 5
reserve_pool_timeout = 3
server_idle_timeout = 300
server_lifetime = 3600

PgBouncer supports three pool modes:

Monitoring Connection Pools

Metrics to watch:

-- MySQL: check active connections
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Threads_running';
SHOW STATUS LIKE 'Max_used_connections';

-- PostgreSQL: check connections
SELECT state, count(*)
FROM pg_stat_activity
GROUP BY state;

-- PgBouncer: check pool stats
SHOW POOLS;
SHOW STATS;

Common Pitfalls

Best Practices

Conclusion

Connection pooling is one of the highest-impact, lowest-effort performance optimizations for database-backed applications. It reduces latency, increases throughput, and protects the database from connection storms. Choose the right pooling strategy for your stack, configure pool sizes carefully, monitor for saturation, and avoid connection leaks. The payoff is immediate and measurable.

Check your website right now

Check now →
More articles: Infrastructure
Infrastructure
Nginx Performance Tuning: Key Configuration Tips
16.03.2026 · 14 views
Infrastructure
Reverse Proxy: How It Works and Why You Need One
16.03.2026 · 20 views
Infrastructure
CDN: How It Works and Why You Need It
14.03.2026 · 12 views
Infrastructure
API Versioning Strategies: URL, Header, and Query Parameter Approaches
16.03.2026 · 24 views