Critical

How to resolve Postgres connection pool exhausted — automated runbook

When your database connection pool fills up, queries queue and apps hang. OnCallReady identifies idle or leaked connections, terminates them, rebalances the pool, and restarts offending services — typically under 25 seconds.

Avg Resolution
22s
Severity
Critical
Success Rate
97%
Humans Paged
0

Trigger Conditions

/db.*(pool|connection|exhausted|timeout|max.conn|too.many)/i

Fires on database connection-related alerts indicating pool saturation or connection leak. Typical triggers: "DB connection pool exhausted on api-server", "Too many connections to PostgreSQL", "Connection timeout after 30s", "Max connections reached (100/100)".

What the Agent Does

1

Query active connections

Runs pg_stat_activity (or equivalent) to enumerate current connections by state, duration, and application. Identifies idle connections, long-running transactions, and potential connection leaks.

2

Terminate idle connections

Issues pg_terminate_backend for connections idle >5 minutes. Preserves active query connections. Frees pool slots immediately without requiring service restarts.

3

Identify and restart connection-leaking services

Cross-references application tags on connections to identify which service is leaking. Performs a rolling restart of that service to reset its internal connection pool state.

4

Verify pool availability

Checks connection count drops below 70% of maximum. Confirms application health endpoints return 200 and database queries complete normally.

5

Log and optionally right-size pool limits

Records freed connection count, offending service, and incident timeline. Flags if the max_connections setting is consistently approached — surfaces this for infrastructure review.

Example Incident Log

incident-5201 · db-connection-pool · prod-db-primary
[11:44:18] ALERT DB connection pool exhausted (100/100) on prod-db-primary
[11:44:18] Matched runbook: db-connection-pool
[11:44:19] Querying pg_stat_activity...
[11:44:20] 62 connections idle >5min · application=api-worker
[11:44:20] 38 connections active · normal query patterns
[11:44:21] Terminating 62 idle connections via pg_terminate_backend
[11:44:22] Freed 62 connections · Pool: 100/100 → 38/100
[11:44:22] Connection leak source: api-worker (v2.3.1) — no pool.release() calls
[11:44:23] Rolling restart of api-worker (2 instances)
[11:44:29] api-worker restarted · Health checks passing
[11:44:30] Pool stable at 24/100 connections
[11:44:40] ✓ RESOLVED Pool: 100/100 → 24/100 · Duration: 22s
[11:44:40] On-call: undisturbed. Connection leak flagged for dev review.

Symptoms

Root cause diagnostic tree

1. SELECT count(*), state FROM pg_stat_activity GROUP BY state
   ├── Most connections idle-in-transaction > 5min → app leak — caller did not COMMIT/ROLLBACK
   ├── Most connections idle → pool sizing too aggressive per app instance
   └── Most connections active long-running → slow query blocking the rest

2. SELECT application_name, count(*)
   FROM pg_stat_activity
   GROUP BY application_name
   ORDER BY count(*) DESC LIMIT 5
   └── Identify the leaking service

3. Decide:
   ├── Idle leak → pg_terminate_backend(pid) for stale sessions
   ├── Slow query → pg_cancel_backend(pid) then optimize
   └── Repeated leak from one service → rolling restart that service

Manual remediation steps

# 1. Inspect active connections
psql -h prod-db-primary -U admin -d app -c "
SELECT pid, usename, application_name, state, query_start, xact_start
FROM pg_stat_activity
ORDER BY xact_start NULLS LAST LIMIT 20;"

# 2. Terminate idle-in-transaction connections older than 5 minutes
psql -h prod-db-primary -U admin -d app -c "
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state IN ('idle', 'idle in transaction')
  AND (now() - state_change) > interval '5 minutes'
  AND pid <> pg_backend_pid();"

# 3. Cross-reference to find the leaking service
psql -h prod-db-primary -U admin -d app -c "
SELECT application_name, count(*)
FROM pg_stat_activity
GROUP BY application_name ORDER BY count(*) DESC;"

# 4. Rolling restart the leaking service
kubectl rollout restart deploy/api-worker

# 5. Verify pool is back below 70% capacity
psql -h prod-db-primary -U admin -d app -t -c "
SELECT count(*) FROM pg_stat_activity;"

How OnCallReady's agent handles this

Playground preview
Auto-remediation plan for DB connection pool exhaustion

Our agent queries pg_stat_activity, bucketing sessions by state and application_name, terminates all idle-in-transaction connections longer than 5 minutes, then cross-references to identify the leaking service. It performs a rolling restart via kubectl rollout restart and verifies pool usage drops below 70% before resolving.

Open in Playground →

Related runbooks

Run this runbook automatically

Stop connection-pool exhaustions before your queries start timing out.