Atatus Database Monitoring offers comprehensive monitoring for your Supabase Postgres databases, providing valuable insights into query performance, query samples, execution plans, connection details, and system statistics.

The Atatus Infra Agent runs on a separate host that connects directly to your Supabase database. For accurate metrics, the Agent must connect to the underlying Postgres host — not via the Supavisor / pgbouncer pool — whenever possible.

Before You Begin

Component Supported Versions / Requirements
PostgreSQL 10, 11, 12, 13, 14, 15, 16, 17
Atatus Infra Agent 3.4.0 or higher

Supabase's default direct connection requires IPv6. Either ensure your Agent host supports IPv6, or enable the IPv4 add-on (available on Pro plans and above).

pg_stat_statements is enabled on Supabase by default. If it isn't, enable it from Database → Extensions in the Supabase dashboard.

Setup Database Access for the Agent

Open the Supabase SQL Editor (or connect via psql with the postgres role) and run the following statements.

Create the atatus user:

copy
icon/buttons/copy
CREATE USER atatus WITH password '<UNIQUEPASSWORD>';

Postgres ≥ 15

Run in every database:

copy
icon/buttons/copy
ALTER ROLE atatus INHERIT;

CREATE SCHEMA atatus;
GRANT USAGE ON SCHEMA atatus TO atatus;
GRANT USAGE ON SCHEMA public TO atatus;
GRANT USAGE ON SCHEMA extensions TO atatus;
GRANT pg_monitor TO atatus;

Postgres ≥ 10

Run in every database:

copy
icon/buttons/copy
CREATE SCHEMA atatus;
GRANT USAGE ON SCHEMA atatus TO atatus;
GRANT USAGE ON SCHEMA public TO atatus;
GRANT USAGE ON SCHEMA extensions TO atatus;
GRANT pg_monitor TO atatus;

Explain Plan Function (All Versions)

Create the explain function in every database:

copy
icon/buttons/copy
CREATE OR REPLACE FUNCTION atatus.explain_statement(
   l_query TEXT,
   OUT explain JSON
)
RETURNS SETOF JSON AS
$$
DECLARE
curs REFCURSOR;
plan JSON;

BEGIN
   OPEN curs FOR EXECUTE pg_catalog.concat('EXPLAIN (FORMAT JSON) ', l_query);
   FETCH curs INTO plan;
   CLOSE curs;
   RETURN QUERY SELECT plan;
END;
$$
LANGUAGE 'plpgsql'
RETURNS NULL ON NULL INPUT
SECURITY DEFINER;

Verify

Confirm the atatus user can connect and read the core tables. Replace <SUPABASE_HOST> with your project's database host (for example, db.<project-ref>.supabase.co):

copy
icon/buttons/copy
psql -h <SUPABASE_HOST> -U atatus postgres -A \
  -c "select * from pg_stat_database limit 1;" \
  && echo -e "\e[0;32mPostgres connection - OK\e[0m" \
  || echo -e "\e[0;31mCannot connect to Postgres\e[0m"

psql -h <SUPABASE_HOST> -U atatus postgres -A \
  -c "select * from pg_stat_activity limit 1;" \
  && echo -e "\e[0;32mPostgres pg_stat_activity read OK\e[0m" \
  || echo -e "\e[0;31mCannot read from pg_stat_activity\e[0m"

psql -h <SUPABASE_HOST> -U atatus postgres -A \
  -c "select * from pg_stat_statements limit 1;" \
  && echo -e "\e[0;32mPostgres pg_stat_statements read OK\e[0m" \
  || echo -e "\e[0;31mCannot read from pg_stat_statements\e[0m"

Configure Atatus Infrastructure Agent

  1. Install the Atatus Infrastructure agent on a host that can reach your Supabase project.

  2. Copy the PostgreSQL example configuration file:

    copy
    icon/buttons/copy
    cd /etc/atatus-infra-agent/conf.d/postgresql.d/
    sudo cp postgresql.yml.template postgresql.yml
    
  3. Update the PostgreSQL configuration file at /etc/atatus-infra-agent/conf.d/postgresql.d/postgresql.yml:

    copy
    icon/buttons/copy
    metrics:
      - hosts: ["<SUPABASE_HOST>"]
        port: 5432
        username: atatus
        password: <UNIQUEPASSWORD>
        ssl: true
        dbm: true
    

    Supabase enforces SSL — ssl: true is mandatory.

  4. Restart the Atatus Infra Agent:

    copy
    icon/buttons/copy
    sudo service atatus-infra-agent restart
    

Connecting via Supavisor Session Pooler (Optional)

If your Agent host cannot reach Supabase's direct connection (for example, because it's IPv4-only and the IPv4 add-on isn't enabled), connect via the Supavisor session pooler instead. The username must be suffixed with your project reference:

copy
icon/buttons/copy
metrics:
  - hosts: ["<SUPABASE_POOLER_ENDPOINT>"]
    port: 5432
    username: atatus.<PROJECT_REF>
    password: <UNIQUEPASSWORD>
    ssl: true
    dbm: true
    reported_hostname: <SUPABASE_HOST>

reported_hostname ensures metrics are tagged to the underlying instance rather than the pooler endpoint.

Collecting Schemas (Optional)

copy
icon/buttons/copy
metrics:
  - hosts:
      - "<SUPABASE_HOST>"
    username: <DB_USERNAME>
    password: <DB_PASSWORD>
    ssl: true
    dbm: true
    db_name: <DB_NAME>
    dbm_postgresql_options:
      collect_database_info:
        enabled: true
        auto_discovery: true
        max_tables: 200
      collect_settings:
        enabled: true
        ignore_patterns:
          - '^pg_toast'
          - '^pg_stat'
          - '^pg_stat_tmp'
          - '^pg_locks'

Collecting Custom Metrics (Optional)

copy
icon/buttons/copy
metrics:
  - hosts:
      - "<SUPABASE_HOST>"
    username: <DB_USERNAME>
    password: <DB_PASSWORD>
    ssl: true
    dbm: true
    db_name: <DB_NAME>
    dbm_postgresql_options:
      additional_metrics_options:
        custom_queries:
          enabled: true
          max_custom_queries: 5
          custom_query:
            - query: |
                SELECT COUNT(*) AS user_count FROM public.users;
              columns:
                - name: user_count
                  type: gauge
              tags:
                - source:custom_user_count