Skip to content

Diagnosing node-postgres connection timeouts at startup

Covers distinguishing pool exhaustion from a genuine reachability/auth failure, which node-postgres reports identically, and the immediate config-side responses to each. Does not cover a pool that starts healthy and exhausts gradually under sustained traffic from a code-level leak — that's the missing-release playbook, a different root cause with the same visible error.

Unverifiedno reproductions yetWhy this confidence?
Revision 1published by DevYou curationrevision history
Run the diagnosisEvidence and compatibility

Symptoms

The diagnostic path

7 steps. Every step is written out below in full — the interactive version simply follows the branches for you.

  1. Step 1 · StartPool.connect (or a query) timed out

    node-postgres uses this same message and the same connectionTimeoutMillis both for establishing a brand-new physical connection and, in recent versions, for a caller waiting in the pool's internal queue for one to become available — so the message alone doesn't tell you which happened.

    What happens next

    • passed step 2, Check whether the pool itself is the bottleneck
  2. Step 2 · TestCheck whether the pool itself is the bottleneck

    Sample the pool's own counters at (or just after) the moment of the timeout.

    Read-onlyjavascript
    console.log({ total: pool.totalCount, idle: pool.idleCount, waiting: pool.waitingCount });

    Expected result

    { total: 10, idle: 0, waiting: 4 }

    What happens next

    • passed step 3, The pool is maxed out and callers are queued
    • failed step 4, The pool never got a connection at all
    • unknown step 4, The pool never got a connection at all
  3. Step 3 · Root causeThe pool is maxed out and callers are queued

    idleCount is 0, totalCount is at (or near) max, and waitingCount is above 0 — every connection is checked out and this caller is genuinely waiting for one. This is most often a burst of concurrent callers at startup (e.g. several parallel health checks or a stampede of cold starts) rather than a leak, since the pool was otherwise healthy moments before.

    What happens next

    • passed step 5, Raise max to match real peak concurrency, or serialise the startup burst
  4. Step 4 · Root causeThe pool never got a connection at all

    If totalCount and idleCount are both near zero and nothing is genuinely waiting on pool capacity, the pool isn't the bottleneck — the underlying TCP/auth handshake itself is failing to complete in time. Check basic reachability from this exact environment (DNS resolution, firewall/security-group egress, TLS requirements) and that credentials are correct, e.g. with psql from the same host. That investigation is outside this playbook.

  5. Step 5 · FixRaise max to match real peak concurrency, or serialise the startup burst

    If many callers open connections concurrently at boot, either raise max to accommodate genuine peak concurrency, or make startup checks share a single connection/query rather than one each. Raising connectionTimeoutMillis alone is only a stopgap — it changes how long callers wait, not how many connections are available.

    Read-onlyjavascript
    const pool = new Pool({ max: 20, connectionTimeoutMillis: 5000 });

    What happens next

    • passed step 6, Re-check pool counters under the same load pattern
  6. Step 6 · Verify the fixRe-check pool counters under the same load pattern

    Reproduce the same startup burst and sample again.

    Read-onlyjavascript
    console.log({ total: pool.totalCount, idle: pool.idleCount, waiting: pool.waitingCount });

    Expected result

    { total: 20, idle: 6, waiting: 0 }

    What happens next

    • passed step 7, Resolved
    • failed step 4, The pool never got a connection at all
    • unknown step 4, The pool never got a connection at all
  7. Step 7 · EndResolved

    waitingCount stays at 0 under the same burst that used to time out.

Sources

Why this confidence?

What would strengthen it: 6 more independent reproductions. Reproductions from 3 more distinct environments.