Cards/DatabasesSystem Design · Day 43Sep 14, 2026

A Connection Costs More Than You Think

Why every Postgres connection is a separate OS process costing megabytes, how 500 connections on 16 cores collapses throughput, where the queue forms under a small pool versus a large one, and a pooler as the fix

Your service has 500 threads. Somebody sets the connection pool to 500 to match, and the database falls over.

In Postgres every connection is a separate operating system process. Several megabytes of memory before it does any work, and one more thing the scheduler has to juggle. Five hundred of them on a sixteen-core machine means five hundred processes taking turns at sixteen seats. Context switching climbs, memory climbs, and throughput goes down rather than up.

The queue never disappears. You only choose where it forms. With a small pool it forms in your application, which is cheap — the database runs at full speed and performance stays predictable. With a large pool it forms inside the database, where connections contend for the same cores and the database itself becomes the bottleneck.

A pooler like PgBouncer lets thousands of client connections share a small number of real ones. Start in the low tens, keep transactions short, and never hold a connection while waiting on an external call.

When something is scarce, the answer is rarely to ask for more of it. It's to hold it for less time.

When something is scarce, the answer is rarely to ask for more of it. It's to hold it for less time.