Pooling was never the hard part
I've always found it a little odd that connection pooling gets filed under "solved."
You put pgbouncer or pgagroal in front of a database, pick a pool size, move the application to the new port, and the connection storm that had been chewing through memory all afternoon quietly goes away. For a single database, that really is the whole story. The idea is decades old, the implementations are good, and none of the pieces are a research problem anymore — transaction pooling, a sane maximum, prefill so the first query of the morning doesn't pay for a cold connection.
So people set one up and stop thinking about it. Honestly, they're right to. The install is easy.
What nobody writes down is everything that happens after the install.
A pooler is a small, quiet process. It sits in a critical path and spends almost all of its time doing nothing interesting, which is exactly why it drifts. One instance gets its max_connections nudged up during a 2 a.m. incident and never nudged back. Another is two point releases behind because a rolling upgrade stalled on a node that had been cordoned for something unrelated, and by morning everyone had moved on. A third has a slightly different pgagroal_hba.conf because a contractor needed one database for one afternoon eight months ago. None of these are outages. Each one is a footnote. Collectively they are the reason your "identical" fleet behaves differently under load and nobody can quite say why.
Then there are certificates.
A single expiring certificate is a calendar reminder. Forty of them, on forty poolers, issued by three different processes across two clusters and a handful of VMs that predate the move to Kubernetes, is a low background hum of anxiety you learn to live with. The failure mode isn't dramatic. It's a Tuesday, one cert lapses, one service can't reach its database, and you spend the first twenty minutes of the incident just working out which pooler in which namespace is the one that's angry.
Somewhere around the third or fourth instance the character of the problem changes, and most teams don't notice the moment it happens. The thing you're operating is no longer a pooler. It's a fleet of them, and a fleet has properties no single instance has.
I've come to think the genuinely interesting distinction in infrastructure isn't between good tools and bad tools. It's between installing something and operating it. Installing is a bounded task with a definition of done. Operating has no done — it's the slow accumulation of every small decision made under pressure, every exception that quietly became permanent, every version that was current the day it was deployed and isn't now. A tool can be excellent and still hand all of that back to you, because the operating part is unglamorous and specific to each shop, and it is genuinely hard to build anything general out of it.
The usual response, once the operating burden gets heavy enough, is to reach for the source. Fork the pooler, bolt on the management glue you need, ship your own build. It feels like taking control. In practice you've signed up to carry a fork. Every upstream fix now has to be rebased onto your changes. Every CVE in the pooler is now partly yours to patch, on your schedule, with your smaller set of eyes on the code. The gap between your build and the real project widens one commit at a time until, a year later, the upgrade you've been putting off is a project of its own. I've watched teams pour more effort into maintaining the fork than they ever spent on the problem the fork was meant to solve.
The better instinct, almost always, is to leave the thing that works alone.
There's a related principle I've grown stubborn about. The software that manages your infrastructure should never sit inside the path that infrastructure serves. A pooler's whole job is to move bytes between an application and PostgreSQL, fast, and to keep doing it. The moment your management layer — the dashboard, the inventory, the reconciler that decides what "correct" config is — ends up in that byte path, you've tied the availability of production to the availability of a control system that has no business being that important. Control planes fail. They get upgraded, they fill a disk, they have bugs. When mine fails I want the only consequence to be that I temporarily can't see or change the fleet. The connections should keep flowing exactly as they did a second earlier. Production software should keep working when the management software disappears — and if it can't, then the management software was never a control plane. It was a single point of failure wearing a nicer name.
Once you've operated more than a few of these, the actual shape of the problem is fairly clear.
The pooler itself is fine. It was fine at one instance and it's still fine at fifty. What's missing is everything around it that has to stay consistent whether you run one or a hundred: knowing what's really deployed and where it has drifted from what you declared, rolling a version change through the fleet as a controlled change that can back itself out instead of a fleet-wide event you hold your breath through, keeping certificates current without a spreadsheet, and producing the boring evidence an auditor asks for without reconstructing it after the fact. And doing all of it from beside the data path, never in it.
That's the problem we ended up building for, and it's the reason pgAgroal Enterprise runs standard pgagroal rather than a fork of it. The pooler in the connection path is the same open-source pgagroal you'd run yourself — hardened container defaults, but the real thing — and it keeps serving connections whether or not the control plane is up. Everything Elevarq adds sits alongside it: a Kubernetes operator with locked-down defaults, fleet inventory and drift detection so that 2 a.m. hand-edit surfaces as a visible deviation instead of a six-month mystery, health-gated upgrades that canary and roll themselves back on failure, signed artifacts with an SBOM and an actual CVE-response process, and a support path that doesn't require handing anyone your credentials or your data.
None of that changes how a single pooler behaves. That's the entire point. It changes how forty of them behave together.
If any of this reads like a Tuesday you've had, the specifics are on the product page. And if you've never had that Tuesday — enjoy it, and maybe keep an eye on how many poolers you're quietly up to now.