How to monitor Postgres and Supavisor connections

Last edited: 1/17/2025

This guide explains how connections impact your Supabase database's performance and how to optimize them for better resource utilization.

Installing Supabase Grafana

Supabase has an open-source Grafana Repo that displays real-time metrics of your database. Although the Reports Dashboard provides similar metrics, it averages the data by the hour or day. Having visuals of your connection usage can help you better allocate resources.

Visual of Grafana Dashboard

image

It can be run locally within Docker. Alternatively, you can deploy it to fly.io or Grafana Cloud, which are better for long-term data collection.

Installation instructions can be found in it the metrics docs

Observing connections

In Supabase Grafana, the "Client Connections" graph shows connections to both Supavisor and Postgres

image

  • Yellow: The yellow line represents the number of actively querying and idle connections to the Supavisor Pooler.
  • Green: The green line represents the total number of actively querying and idle direct connections to the database.

Investigating connection sources

pg_stat_activity is a VIEW that keeps track of processes being run by your database, including connections. It's particularly useful for determining if idle clients are hogging connection slots.

This is a query you can use to observe the database roles and servers connecting to your database:


_14
SELECT
_14
pg_stat_activity.pid,
_14
ssl AS ssl_connection,
_14
datname AS database,
_14
usename AS connected_role,
_14
application_name,
_14
client_addr,
_14
query,
_14
query_start,
_14
state,
_14
backend_start
_14
FROM pg_stat_ssl
_14
JOIN pg_stat_activity
_14
ON pg_stat_ssl.pid = pg_stat_activity.pid;

Interpreting the query:

ColumnDescription
pidconnection id
sslIndicates if SSL is in use
datnameName of the connected database (usually postgres)
usenameRole of the connected user
application_nameName of the connecting application
client_addrIP address of the connecting server
queryLast query executed by the connection
query_startTime when the last query was executed
stateQuerying state: active or idle
backend_startTimestamp of the connection's establishment
  • Note: If you are unfamiliar with the Supabase database roles, check this reference

If you believe a connection should be killed, you can do so by running the following query:


_10
select pg_terminate_backend(pid)
_10
from pg_stat_activity
_10
where pid = <connection_id>;

Managing the Supavisor pooler:

The Supavisor Pooler is an intermediary between your clients (application servers) and the database. In transaction mode (port 6543), it can enable Postgres to share single connections with many clients, only allowing access when a query is pending. This prevents idle clients from hogging a direct connection and allows for more throughput.

In cases where you see significantly more pooler connections than direct connections, if you can, you should consider increasing how many direct connections the pooler is allowed to manage in the Dashboard's Database Settings:

image.

The general rule is that if you are using the PostgREST database API, you should avoid raising your pool size past 40%. Otherwise, you can commit 80% to the pool. This leaves adequate room for the Authentication server and other utilities.

These numbers are generalizations and assume a certain level of activity from all connected servers. The actual values depend on your peak connection usage. For instance, if you were only using 80 connections in a week period and your database could support 500 connections, then realistically you could allocate the remaining 420 (minus a reasonable buffer) to service more demand.

Secondary issues:

When managing Postgres, outside of connections, there are generally 3 likely bottlenecks (links to address each):

They're all intertwined to some extent. If IO, CPU, or Memory are constrained, this can cause queries to slow down. Your application servers and Supavisor may compensate by creating more database connections or letting queries wait longer in their respective queues. Sometimes, by addressing or optimizing other factors of the database, you can better address connection issues.

Other helpful resources: