Connection Pool Exhausted
Connection pool sizing, max_connections, PgBouncer, RDS Proxy, idle connections, and leak detection.
Overview
Overview
Database connection pools are finite. When the pool is exhausted, new requests queue for a connection, and past the timeout they fail with "connection pool timeout" or "too many connections". This is one of the most common causes of database outages during traffic spikes.
The math
max_connections defaults to 100 in stock PostgreSQL; RDS derives its default from instance memory. Each connection uses approximately 5-10 MB of RAM on the database server, and the total across all application instances must stay below max_connections.
- 50 app instances × pool of 10 — 500, five times a limit of 100
- Same, behind a connection pooler — Many app connections multiplexed onto far fewer database connections
PgBouncer pooling modes
- Session — One database connection per client session, same as no pooling — Everything works
- Transaction — The connection returns to the pool after each transaction; N app connections share far fewer database connections — Prepared statements and advisory locks need session mode
- Statement — Most aggressive — Limited
Failure mechanism: a connection leak
> [!TIP] Monitor idle connections in pg_stat_activity; if idle connections match the pool maximum, there is likely a leak.
Key concepts
- max_connections
- PostgreSQL hard limit on simultaneous database connections. Exceeding it causes "FATAL: sorry, too many clients already". Each connection uses ~5-10 MB. Increase with caution.
- PgBouncer transaction mode
- Assigns a database connection only during a transaction. Allows 100 app connections to share 10 database connections if queries are short. Incompatible with prepared statements and session-level settings.
- Connection leak
- Application code that opens a connection but fails to close it on error paths. Connections fill the pool until it is exhausted. Detect with pg_stat_activity: SELECT count(*), state FROM pg_stat_activity GROUP BY state.
- RDS Proxy
- AWS-managed connection pooler for RDS/Aurora. Integrates with IAM authentication, Secrets Manager rotation. Particularly valuable for Lambda functions that cannot maintain connection pools between invocations.
- Pool sizing formula
- Empirical rule: pool size = ((core_count * 2) + effective_spindle_count). For a 4-core database server with SSDs: pool per app instance = 9. Total connections = 9 * app_instances.
When to use it
- Diagnosing "too many connections" errors during a traffic spike
- Sizing a connection pool for a microservice at scale
- Implementing PgBouncer or RDS Proxy to support Lambda or serverless workloads
- Finding a connection leak in an application that slowly accumulates idle DB connections
Interview questions
- Your application is getting "too many connections" errors during a traffic spike. How do you resolve it immediately and prevent it long-term?
Sign up free to read the full topic
More Troubleshooting topics
- Alert Fatigue and On-Call Burnout
- Alerts Not Firing
- Canary Deployment Problems
- CoreDNS Failures in Kubernetes
- CPU Runaway Process Investigation
- CrashLoopBackOff
- Database Deadlock Diagnosis
- Database Migrations in Production
- Deployment Rollback Strategies
- Disk IOPS Saturation
- DNS Failures
- EC2 Instance Unresponsive
Start free on Cariara · Coding problems · System design studio