Database Sizing and Connection Management
Right-size the box and tame the connections
Sizing databases means instance shape, storage and IOPS for the workload — and connection management is where many 'database is down' incidents actually live: exhausted max_connections, connection storms and pool mishaps.
What you will learn
- Size instance and IOPS from workload metrics
- Explain the connection-budget and pool math
- Operate PgBouncer/Proxy/connection multiplexing
A database instance has capped connections, memory and I/O. Sizing matches those limits to real patterns; pooling amortizes connections so 1,000 app pods share 50 sockets without 'too many connections'.
What is this?
Sizing: instance shapes (db.t3.medium → io2 provisioned IOPS), storage class, and instance reconfiguration. Connection math: Postgres max_connections ~ hundreds; serverless pools and PgBouncer (transaction pooling) aggregate; Aurora/Azure have serverless/connection proxies; MySQL Threads_connected, wait_timeout tuning. Sizing signs: hit max_connections → pool; slow query → index/IOPS; memory pressure → buffer/instance size.
Why do you need it?
- Exhausting connections is the classic 'DB looks down' production incident.
- Connection pooling cuts RAM-per-socket and network churn dramatically.
- Right-sizing prevents throttle-hitting IOPS at the worst moment.
- Interview staple: walk through 'too many connections' end to end.
Mental model
A phone switchboard with limited trunk lines
Connection pooling
Thousands of calls (app requests) share dozens of trunk lines (pooled connections); the switchboard (pool) queues and multiplexes instead of giving every caller a private handset connection.
How it works
- Every connection costs memory (rdbuffers, stacks); max_connections bounds concurrency.
- A pool keeps N sockets alive and lends them per-transaction (transaction pooling) or per-session.
- Poolers (PgBouncer, Azure SQL connection pooling, Aurora read/write endpoints) manage multiplexing and limits.
- wait_timeout/idle_in_transaction_session_timeout evicts idle drains.
- Sizing: compute typical concurrent ops + idle review budget; scale read replicas for read-heavy splits.
Connection pooling path.
Examples
Pool and sizing in practice
# PgBouncer transaction pooling dest:# pools 100 app pods to 20 server connectionspgbouncer.ini:[databases]app = host=db.rds pool_mode=transaction max_client_conn=200[pgbouncer]default_pool_size = 20# app config: connect to pgbouncer:6432, not the DB:5432# Postgres: bound the DBALTER SYSTEM SET max_connections = 200;UPDATE pg_settings_value ... -- careful; restart for effectClient pods connect to the pool; the pool keeps a small warm set of real DB sockets.
In production
- A 200-pod app fronts Aurora with PgBouncer (max_client_conn=200, default_pool_size=40).
- Azure SQL uses the built-in connection pooling + MAX_CONNECTIONS bound per DTU.
- A MySQL shop times out idle connections at 60s and pools via ProxySQL.
Best practices
- Pool before you scale: a pool fixes the connection dimension without buying IOPS.
- Set sane client idle timeouts and transaction-idle limits at the DB.
- Size IOPS from p99 (burst) and connections from concurrent pods × app concurrency.
- Keep pooling + read/write split visible; route reporting to replicas through the pool too.
Common mistakes
- Bumping max_connections instead of pooling — memory for sockets, then OOM.
- A connection per request in the app (churn kills pool efficiency and adds latency).
- Pool sized to 'nice to have' rather than peak concurrency × readiness spike.
- Altering parameters without restart planning → half the config never applied.
Common issues
Too many connections errorPool too small or app leaks connections
Enlarge pool client conns, set idle timeouts, find and fix the leak before touching max_connections.
Pool starves during deploy restartsSudden connection storm (all pods racing)
Stagger deploys, cap app-side pool size, and warm the pool before the burst.
Debugging tips
- 'too many connections': check the pool/active sessions, then look at RUNNING queries not just count.
- Connection leaks: session that never closes → max idle; set idle limits and watch pool metrics.
- Sizing regression: compare IOPS baseline, latency p99, and 'idle in transaction' count.
- If requests queue at the pool, see whether app-side connection limit or DB query time is the real bound.
Interview checkpoint
Quick quiz
What does transaction pooling do with a client connection?