Does anyone run Postgres without PgBouncer?
Is Anyone Actually Running Postgres Without PgBouncer?
Originally inspired by a discussion on brandur.org
On a recent weekend, I received a shout-out from Ben Dicken regarding a piece I wrote nearly a decade ago about the intricacies of managing database connections.
(Side note: Ben is essentially the Mick Jagger of the database world; I've never seen my LinkedIn invitations spike quite like that in a single day.)
The most jarring realization wasn't just that the article is years old, but that the core advice remains entirely relevant.
The Persistent Problem
Postgres is still notoriously inefficient at handling a massive volume of concurrent connections. To maintain stability, the industry standard remains a combination of:
- Implementing local connection pools.
- Ensuring short-term checkouts.
- Deploying a middleware pooler like
PgBouncer.
This led me to wonder: Is using a pooler actually the norm, or just a common recommendation?
Market Analysis: Managed Provider Support
To find out, I audited the most prominent managed Postgres services to see if they provide native pooling capabilities.
| Provider | Implementation | Availability / Caveats |
|---|---|---|
| Aiven | ✅ PgBouncer | Available on Startup plans+ |
| Alibaba RDS | ✅ PgBouncer | Included |
| AWS RDS / Aurora | ✅ RDS Proxy | Offered as a separate managed service |
| Azure PG | ✅ PgBouncer | Included |
| ClickHouse Managed PG | ✅ PgBouncer | Currently in public beta |
| Crunchy Bridge | ✅ PgBouncer | Included |
| DigitalOcean | ✅ PgBouncer | Included |
| EDB Postgres AI | ✅ PgBouncer | Included |
| Fly.io MPG | ✅ PgBouncer | Included |
| Google Cloud SQL | ✅ PgBouncer | Requires Enterprise Plus for managed pooling |
| Heroku | ✅ PgBouncer | Limited to specific plans |
| ❌ — | Self-managed only | |
| Neon | ✅ PgBouncer | Included |
| ❌ — | No managed pooler provided | |
| PlanetScale | ✅ PgBouncer | Included |
| Railway | ✅ PgBouncer | Deployed as a separate service |
| Render | ✅ PgBouncer | Available on paid tiers |
| Supabase | ✅ PgBouncer / Supavisor | Supavisor is their proprietary serverless pooler |
| Tiger Cloud | ✅ PgBouncer | Included |
The Verdict: Not only is PgBouncer ubiquitous, but almost every provider bundles it. If we ignore IBM and Oracle (services typically only touched during grueling enterprise sales cycles), 100% of viable managed Postgres providers include a pooler.
The "Windshield" Analogy
One might argue that this setup is acceptable because the tools exist. However, consider this scenario:
Imagine visiting a car dealership and being sold a vehicle without a windshield. You notice that every other car on the road has one, and you quickly realize that driving without one is totally fine extremely dangerous.
Because you signed the contract, it is technically your responsibility to install a windshield before driving. But you'd still be rightfully annoyed that the dealer sold you a car that wasn't "road-ready" the moment it left the lot.
The Current Workflow
Right now, using Postgres is like installing that aftermarket windshield. Users must:
- Navigate provider-specific setup guides.
- Configure separate ports for the database vs. the bouncer.
- Study the specific limitations of
PgBouncer(e.g.,LISTEN/NOTIFYissues). - Balance the trade-offs between different pooling modes.
The Path Forward: Reintegration
What if we had a world where a Postgres provider gave you one URL, one port, and zero caveats?
In this ideal state, the "windshield" is built into the car. We know this is possible because it is the default experience in the MySQL and MongoDB ecosystems.
The technical barrier is the ancient "processes vs. threads" architectural debate. Very few people in the community have the political capital to force a fundamental change in how Postgres handles concurrency. However, given the staggering amount of human effort spent building workarounds, integrating native pooling would be one of the most impactful operational upgrades in the history of the project.
The Mathematical Reality
The overhead of a Postgres connection can be viewed as a linear cost: Where is the number of connections. By moving to a threaded or integrated pooling model, we could reduce the constant significantly.
-- Current reality: managing two different connection strings
-- Direct: postgres://user:pass@db-host:5432/db
-- Pooled: postgres://user:pass@bouncer-host:6432/db
![]()