# PostgreSQL Connection Pooling Best Practices

**Sources:**
- [Why you should use Connection Pooling when setting Max_connections in Postgres (EDB)](https://www.enterprisedb.com/postgres-tutorials/why-you-should-use-connection-pooling-when-setting-maxconnections-postgres)
- [Connection pooling best practices - Azure Database for PostgreSQL (Microsoft)](https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-connection-pooling-best-practices)

**Authority Tier:** 2 (Vendor - Industry best practices from EDB and Microsoft)

## max_connections Configuration

### Optimal Connection Limits

**Empirical Results:** Testing on a 32-CPU, 244GB RAM server showed that "optimal performance was when there were 300-500 concurrent connections." Performance degraded significantly above 700 connections, with the sweet spot identified as 300-400 concurrent connections.

### Industry Guidelines (Validated)

The following expert recommendations were tested and confirmed:
- "a few hundred" concurrent connections
- "not more than 500" connections
- "definitely no more than 1000" connections

### Default Configuration

- **PostgreSQL default:** 100 connections
- **Rationale:** Conservative but safe for most workloads
- **Recommendation:** Benchmark and adjust based on workload

## Cost of High max_connections Settings

Setting max_connections excessively high creates multiple performance penalties:

### Connection Overhead

"For every connection that is created, the OS needs to allocate memory to the process that is opening the network socket, and PostgreSQL needs to do its own under-the-hood computations"

### Resource Contention

- Disk I/O contention
- OS scheduling conflicts
- CPU-level cache-line contention

### Memory Consumption

- **Each active connection:** ~10 MB of RAM
- **Each connection creates a process:** Can exhaust available resources
- High connection counts can lead to memory exhaustion

### Latency Degradation

Non-linear increases in response times beyond optimal thresholds

## Best Practice Approach

### Configuration Methodology

1. Conduct site-specific benchmark testing using realistic workloads
2. Determine maximum sustainable concurrency
3. Round upward to the nearest hundred for headroom
4. Configure max_connections to that value

### Connection Pooling Strategy

For applications requiring more concurrent user sessions than max_connections allows:

- Implement **pgbouncer** or **pgpool**
- Configure `max_db_connections = 300` (or similar based on testing)
- Maintain database connection limits while accepting thousands of client connections through connection sharing

## PgBouncer Pooling Modes

### Session Pooling

- Server connection assigned for entire client session duration
- Default mode for Open Source PgBouncer
- Connection returned to pool upon client disconnection

### Transaction Pooling (Recommended)

- Server connection dedicated during transaction only
- Released after transaction completion
- **Default for Azure Database for PostgreSQL**
- **Limitation:** Does not support prepared transactions

### Statement Pooling (Advanced)

- Server connection allocated per individual statement
- **Limitation:** Does not support multi-statement transactions
- Use with caution for simple, stateless queries only

## Pool Sizing Configuration

### Initial Pool Size

**Recommendation:** Start with a pool size of about **half your available connections** and adjust based on performance monitoring.

### Configuration Tuning

Administrators must:
- Carefully tune PgBouncer configuration to match application requirements
- Account for connection limits and pool sizing parameters
- Consider the server's capacity when determining pool size
- Monitor to prevent PgBouncer from becoming a bottleneck

## Connection Lifecycle Management

### Idle Connection Handling

- Built-in PgBouncer provides improved management of idle and short-lived connections
- Reduces resource consumption by reusing connections rather than creating new ones

### Connection Validation

- Pools should validate connections before checkout
- For PostgreSQL: Use `SELECT 1` or connection-level validation
- Prevents stale connections from being returned to applications

## High-Availability Best Practices

### PgBouncer Deployment

- **Deploy multiple PgBouncer instances behind a load balancer** to mitigate single points of failure
- Built-in PgBouncer provides seamless HA support
- Connections automatically re-establish after failover without application changes

### Failover Behavior

- Connections must be re-established after server restarts during scale operations
- Automatic reconnection after HA failover (with properly configured pooler)

## Configuration Constraints

### Burstable Compute Tier

**Warning:** PgBouncer is not supported with Burstable compute tier. Users lose PgBouncer capability if migrating to Burstable tier.

## Prescriptive Statements for Claims

1. **MUST NOT exceed 1000 connections:** max_connections should never exceed 1000 for stability
2. **SHOULD target 300-500 connections:** Optimal performance occurs at 300-500 concurrent connections
3. **MUST configure connection pooling:** Applications requiring high concurrency must use pgbouncer or pgpool
4. **SHOULD set pool size to half max_connections:** Initial pool size should be approximately 50% of available connections
5. **MUST validate connections:** Pools must validate connections before checkout to prevent stale connection errors
6. **MUST handle idle connections:** Pools should reclaim idle connections to prevent resource exhaustion
7. **SHOULD use transaction pooling:** Transaction pooling is recommended for most applications (vs session pooling)
8. **MUST deploy HA poolers:** Production deployments should use multiple pooler instances for high availability
9. **MUST account for memory per connection:** Each connection consumes ~10 MB RAM; total must not exceed available memory
10. **SHOULD benchmark before production:** max_connections must be determined through workload-specific testing
