At a glance
The share of your PostgreSQL connection budget that is already spoken for. Vortex IQ takes the count ofactiveplusidle in transactionbackends and divides it bymax_connections. At 100% the next client that tries to connect is refused withFATAL: sorry, too many clients already, and from the application’s point of view the database is down even thoughpostgresis healthy. This is the single most common way a busy PostgreSQL instance falls over, which is why it sits at the top of the Capacity panel.
Calculation
The gauge is computed live as:active_backends=count(*) FROM pg_stat_activity WHERE state = 'active'idle_in_tx_backends=count(*) FROM pg_stat_activity WHERE state = 'idle in transaction'(plus'idle in transaction (aborted)')max_connections= the server’s hard ceiling fromSHOW max_connections
max_connections is not the number the application can use. PostgreSQL reserves superuser_reserved_connections (default 3) so a superuser can always log in to fix a mess, and replication and some background workers also draw from the budget. Vortex IQ divides by the raw max_connections so the gauge matches the figure PostgreSQL itself enforces, but the practical ceiling for ordinary clients is slightly lower. That is why we alert at 90% rather than 100%: the last few percent are effectively unusable.
When a PgBouncer pool is present, the database-facing server_lifetime connections are usually a small, fixed set, so PostgreSQL’s own saturation stays low while the pooler’s client-side pool is the thing that fills up. In that topology this card stays calm and the pooler series is the one to watch. See PgBouncer Pool Saturation vs Traffic Burst.
Worked example
A platform team runs a primary PostgreSQL 15 instance on a managed service backing an order-management API.max_connections is set to 200. Snapshot taken on 14 Apr 26 at 19:45 BST, during an evening sales push.
The numerator is
138 + 51 + 2 = 191. Divided by 200, that is 95.5% saturation. The gauge is red and the > 90% alert has fired.
Two signals jump out. First, the raw pressure is genuinely high: 138 active backends means the instance is doing a lot of real work. But second, and more interesting, 53 backends are idle in transaction or aborted. Those are connections that opened a transaction, ran a statement, then went quiet without committing or rolling back, usually because the application is doing slow work (an external API call, a report render) inside a database transaction. They are holding a pool slot and any locks they took, contributing nothing.
- Immediate relief: kill the worst
idle in transactionoffenders.SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle in transaction' AND state_change < now() - interval '5 minutes';reclaims roughly 40 slots in one shot, dropping saturation to about 75%. Pair this with Idle-in-Transaction Backends. - Structural fix: the real cause is the application holding transactions open across external calls. The fix is in the application (commit before the slow call, not after), not in the database. Raising
max_connectionswould only delay the next wall and costs memory: each backend reserveswork_memand more. - Right architecture: put PgBouncer in transaction-pooling mode in front of the instance so 2,000 application clients can share 200 server connections. After that, this card stays green and the pooler card becomes the one to watch.
max_connections.
Sibling cards
Reconciling against the source
Where to look in PostgreSQL itself:RunWhy our number may legitimately differ from a hand count:SELECT count(*), state FROM pg_stat_activity GROUP BY state;to see the live breakdown by backend state. Add theactiveandidle in transactionrows and divide by the value ofSHOW max_connections;to reproduce the gauge by hand. RunSELECT * FROM pg_stat_database WHERE datname = current_database();for connection-level counters at the database level. On a managed service, the console exposes the same figure as a “Database Connections” metric: AWS RDS / Aurora publishesDatabaseConnectionsin CloudWatch, Google Cloud SQL publishesdatabase/postgresql/num_backends, and Azure Database for PostgreSQL publishesactive_connections.
Known limitations / FAQs
The gauge says 95% but the application is not erroring. Are we safe? You are close to the edge, not over it. Refusals only start at the practical ceiling (max_connections minus reserved and replication slots). At 95% you have a handful of slots left, which one bad deploy, a connection leak, or a traffic burst can consume in seconds. Treat 90%+ as “act now”, not “wait for errors”.
Should I just raise max_connections to make this go away?
Rarely the right move. Every connection reserves memory (work_mem per sort or hash, plus per-backend overhead), so raising the ceiling can push the instance into swapping, which is far worse than connection refusals. The correct fix for sustained saturation is a connection pooler (PgBouncer in transaction mode) and fixing whatever holds connections open. Watch Memory Usage % before and after any change.
Why are idle in transaction backends counted but plain idle ones are not?
A plain idle backend is reclaimable: the pooler or the next request can reuse it immediately, and it holds no locks. An idle in transaction backend is the dangerous kind: it is sitting on an open transaction, holding any locks it took and pinning a slot, often because the application started a transaction and then went off to do slow non-database work. That is the pressure this card is built to surface.
We run PgBouncer. This card stays green even under heavy load. Is it broken?
No, that is expected and correct. With PgBouncer in transaction-pooling mode, a small fixed set of server connections handles thousands of client connections, so PostgreSQL’s own saturation stays low. The saturation that matters in that topology is the pooler’s client-side pool, which Vortex IQ tracks separately. Use PgBouncer Pool Saturation vs Traffic Burst.
Does this include connections from read replicas or the standby?
The gauge is per-instance. The walsender backends that stream WAL to standbys do appear in the primary’s pg_stat_activity and count toward its ceiling, so a primary with several streaming standbys carries a small fixed overhead. Each replica’s own client connections are measured against that replica’s ceiling, not the primary’s.
The managed-service console shows a different connection count than this card.
Common and usually benign. Managed services run their own maintenance and monitoring backends that occupy slots, and some console metrics report against the practical ceiling (after reserved connections) while Vortex IQ divides by raw max_connections. Reconcile by running SELECT count(*), state FROM pg_stat_activity GROUP BY state; directly: that is the ground truth both numbers derive from.
Can I change the 90% alert threshold?
Yes. The threshold is configurable per profile in the Alert Rules tab. A read-heavy reporting database with a generous ceiling and a pooler in front might tolerate 95%; a tightly provisioned OLTP primary might want to alert at 80% to leave room for failover reconnection storms. Set it to your real baseline rather than the generic default.