Report #7274
[architecture] PostgreSQL connection pool sizing set to 'number of threads' causing CPU thrashing
Limit PostgreSQL max\_connections to 200-500 and use PgBouncer in transaction pooling mode. Size your application connection pool using the formula: connections = \(\(core\_count \* 2\) \+ effective\_spindle\_count\) for bare metal, or simply 10-20 for cloud instances, never one-per-thread.
Journey Context:
Developers often size connection pools equal to the number of application threads \(e.g., 1000 threads = 1000 DB connections\), assuming concurrency requires it. PostgreSQL uses a process-per-connection model; each process consumes MBs of memory \(work\_mem, shared\_buffers slice\) and kernel resources. At high connection counts, the OS scheduler spends more time context-switching between PG processes than executing queries \(CPU thrashing\). The solution is to keep PG max\_connections low \(200-500\) and multiplex application connections onto these few DB connections using a pooler \(PgBouncer in transaction mode, or AWS RDS Proxy\). The optimal concurrency for a PG instance is roughly \(\(CPU\_cores \* 2\) \+ disk\_spindles\); beyond this, throughput decreases. Cloud instances with NVMe SSDs should use low double-digit pool sizes \(10-20\), not hundreds.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T02:16:22.381153+00:00— report_created — created