At a glance
How full your Supabase connection pool is. Supavisor is Supabase’s cloud-native connection pooler: it sits between your application and Postgres and multiplexes many client connections onto a smaller set of real database connections. Postgres can only handle a bounded number of direct connections (each one is a process that costs memory), and every Supabase tier has a hard connection cap. Supavisor lets hundreds or thousands of clients share that capped pool. This card shows how much of the pool is in use. At 90% you are one traffic burst away from clients being unable to get a connection at all, which means queries queue, time out, and the app starts throwing connection errors.
Calculation
The gauge is the ratio of in-use pooled connections to the pool’s maximum:- Pool max size is the ceiling Supavisor is configured to hold open to Postgres. It is bounded above by the tier’s hard connection cap: Free and Pro tiers permit a small number of direct Postgres connections, while larger compute tiers allow more. You cannot pool your way past the underlying Postgres cap; Supavisor lets many clients share the capped connections, but the capped number is still the ceiling.
- Active server connections is the count Supavisor currently has checked out doing work. In transaction-mode pooling (the most efficient mode), a connection is held only for the duration of a transaction and returned immediately, so a small pool can serve a large number of brief clients.
- Client connections (the front side, what your app opens) can vastly exceed server connections because Supavisor multiplexes them. This card measures the server side (the scarce resource), not the client side.
LISTEN/NOTIFY, but it saturates the pool far faster because each client monopolises a server slot for its entire lifetime).
The alert uses a 1-minute sustained view: a momentary touch of 90% from a single burst is normal, but 90% held for a minute means the pool genuinely lacks headroom. The card reads the live ratio so you can watch it climb in real time during a traffic ramp.
Worked example
A platform team runs a flash-sale storefront on Supabase Pro. The app is serverless (each function instance opens its own client connection), so they route everything through Supavisor in transaction mode. Their pool max is 60 server connections. Snapshot reviewed on 25 Apr 26 at 19:00 BST, two minutes into a scheduled drop.
At 19:00 the card read 95% and at 19:01 it pinned at 100%. The flash sale drove client connections from 480 to 1,680 in two minutes. Supavisor multiplexed them onto the 60-connection pool fine until demand for concurrent server connections exceeded 60, at which point new requests queued and then timed out. The database CPU and memory were both healthy; the bottleneck was purely the pool ceiling, which on Pro is bound by the tier’s connection cap.
- Immediate: shed load by reducing the number of queries per page request, so each server connection was held for less time and the pool churned faster, which dropped saturation from 100% to about 78% within a minute.
- Same day: added a
statement_timeoutso a single slow query could not occupy a pool slot indefinitely and starve everyone else. - Before the next drop: resized compute to a tier with a higher connection cap, lifting the pool max so the same burst left headroom.
- The pool can be the outage even when the database is fine. CPU and memory were healthy throughout; the storefront still went down because there were no connection slots. Watch this card as closely as the resource gauges.
- Tier caps the pool. On Free and Pro the hard connection cap is low, so a modest burst saturates the pool. You cannot pool past the cap; if you genuinely need more concurrent connections, you need a bigger tier.
- Hold time is your lever. Saturation is concurrency times hold time. Shorter transactions (fewer queries per request, a
statement_timeout, transaction-mode pooling) free slots faster and let a small pool serve far more clients.
Sibling cards
Reconciling against the source
Where to look in Supabase’s own tooling:Project Dashboard → Database → Connection Pooling for the pooler configuration: the pool mode (transaction/session), pool size, and the connection string clients should use. This confirms the denominator the percentage is based on. Project Dashboard → Reports → Database for the connection-count charts over time, including pooler client and server connections. SQL Editor withWhy our number may legitimately differ from the Supabase UI:select count(*) from pg_stat_activity;for the live count of backend connections on Postgres, andshow max_connections;for the underlying cap, to cross-check the pool ceiling against the database cap.
Cross-connector reconciliation: correlate saturation spikes with your front-end traffic source. If saturation climbs in step with a marketing-driven traffic burst (a campaign launch, a flash sale, an email send), that is expected load and the answer is capacity. If saturation climbs with flat front-end traffic, suspect a connection leak in the app (connections opened and never returned) or a long-running query hogging slots; that is a code fix, not a scaling one.
Known limitations / FAQs
My app shows “remaining connection slots are reserved” or pooler timeouts. Is that this card? Yes, that is the pool exhausting. When saturation hits 100%, new connection requests queue and then time out, and Postgres refuses direct connections once the cap is reached. Check this card at the time of the errors: a reading at or near 100% confirms it. The fix is to reduce hold time (shorter transactions, astatement_timeout), pool harder, or resize to a tier with a higher cap.
The database CPU and memory look fine but the app is down. How?
Pool exhaustion is an outage that does not touch CPU or memory. The database can be idle and the storefront still fail because there are no connection slots to run even a trivial query. This card exists precisely to catch that failure mode, which the resource gauges miss. Always read pool saturation alongside CPU and memory, not instead of them.
What is the difference between client and server connections?
Client connections are what your app opens to Supavisor; server connections are what Supavisor opens to Postgres. Supavisor multiplexes many clients onto few server connections, so you might have 2,000 clients and 60 server connections. This card measures the server side because that is the scarce, capped resource. A huge client count is fine as long as server saturation stays under 90%.
Should I use transaction mode or session mode?
Transaction mode for almost everything, especially serverless and high-concurrency apps: it returns the server connection after each transaction, so a small pool serves many clients. Use session mode only when you need session-scoped features (some prepared-statement patterns, LISTEN/NOTIFY, advisory locks held across statements). Session mode saturates the pool far faster because each client monopolises a slot for its whole lifetime.
I increased the pool size but it still saturates. Why?
The pool cannot exceed the tier’s hard Postgres connection cap. If your pool max is already at the cap, raising the configured pool size does nothing; you are bounded by max_connections on the instance. To genuinely add capacity you need a larger compute tier (which raises the cap), or you need to cut connection demand (shorter transactions, fewer queries per request, fixing leaks).
Can I tune the 90% alert threshold?
Yes, in the Alert Rules tab. A spiky, bursty workload should alert earlier (say 80%) to give lead time before a burst pins the pool. A steady workload with predictable load can sit at 90%. Avoid going much higher: above 90% there is very little headroom, so the alert needs to fire while you still have time to shed load or scale.
Direct connections from a tool (psql, a migration runner) seem to push me over. Do they count?
They consume the underlying Postgres connection cap even though they bypass the pooler, so they reduce the slots available to the pool. A migration runner or a BI tool holding several direct connections can make the pool exhaust below 100% pool-saturation because the real cap is shared. Route application traffic through Supavisor and keep direct-connection tools to a minimum during peak windows.