---
title: "How we scale PgBouncer in ClickHouse Managed Postgres"
description: "PgBouncer is single-threaded, so a single process can bottleneck connection pooling on multi-vCPU machines even when Postgres has capacity. ClickHouse Managed Postgres runs a fleet of PgBouncer processes sized to available cores, sharing one port through so_reuseport; peering forwards query-cancellation requests to the process that owns the session, while transaction pooling and per-process connection-budget splits limit Postgres connections. In tests on identical AWS EC2 c7i.4xlarge pooler instances, a 16-process fleet reached roughly 336,000 transactions per second at 256 clients, compared with 76,893 for one process, while using about 49% versus 8% in-guest CPU. The fleet's advantage emerged under concurrency, whereas the single process was slightly faster at eight clients, and the described setup ships by default with every ClickHouse Managed Postgres server."
---

# How we scale PgBouncer in ClickHouse Managed Postgres

[Clickhouse](https://yomu.fyi/company/clickhouse) · Jul 1, 2026

**Type:** Benchmark

## Summary

PgBouncer is single-threaded, so a single process can bottleneck connection pooling on multi-vCPU machines even when Postgres has capacity. ClickHouse Managed Postgres runs a fleet of PgBouncer processes sized to available cores, sharing one port through so\_reuseport; peering forwards query-cancellation requests to the process that owns the session, while transaction pooling and per-process connection-budget splits limit Postgres connections. In tests on identical AWS EC2 c7i.4xlarge pooler instances, a 16-process fleet reached roughly 336,000 transactions per second at 256 clients, compared with 76,893 for one process, while using about 49% versus 8% in-guest CPU. The fleet's advantage emerged under concurrency, whereas the single process was slightly faster at eight clients, and the described setup ships by default with every ClickHouse Managed Postgres server.

## Context

A single PgBouncer process uses one CPU core regardless of the machine's size, causing the pooler to cap throughput before Postgres reaches its capacity. With so\_reuseport, query-cancellation requests can arrive at a different PgBouncer process from the one holding the session, so cancellation can fail without coordination between processes.

## Approach / What changed

Run a fleet of PgBouncer processes sized to the available cores, with every process binding the same port through so\_reuseport. Enable peering so processes forward cancellation requests to the session-owning process. Use transaction pooling and divide max\_client\_conn and max\_db\_connections across the fleet to keep aggregate connections within safe limits.

## Takeaways

- so\_reuseport lets multiple PgBouncer processes share one endpoint while the kernel distributes incoming connections across them, allowing pooling work to use multiple CPU cores.
- PgBouncer peering forwards a query-cancellation request when it reaches a process that does not own the target session, preserving cancellation across the fleet.
- At 256 clients, the 16-process fleet delivered 336,469 transactions per second versus 76,893 for one process, with measured pooler-box CPU of 48.9% versus 7.7%.

**Tags:** [Architecture](https://yomu.fyi/topic/architecture), [Performance](https://yomu.fyi/topic/performance), [Postgres](https://yomu.fyi/topic/postgres), [Scalability](https://yomu.fyi/topic/scalability)

- Source: [Clickhouse](https://clickhouse.com/blog/pgbouncer-clickhouse-managed-postgres)
- Source URL: https://clickhouse.com/blog/pgbouncer-clickhouse-managed-postgres
- Ingested by Yomu: 2026-08-29T01:37:30.571Z

[Read original post](https://clickhouse.com/blog/pgbouncer-clickhouse-managed-postgres)
