Skip to main content

How-to guide

Create the monitoring role

Elevarq Signals connects to each PostgreSQL target as a single, dedicated login role. This guide creates that role with least-privilege, read-only access — the role can read statistics and settings but cannot modify your data or schema. You run it once per database cluster.

Signals reads statistics only — it never modifies your data or schema. The least-privilege way to grant the read access it needs is the built-in pg_monitor role. This is a one-time setup per cluster. For why the role is read-only and how the daemon enforces that at runtime, see why read-only. For how to supply the resulting credential to Signals, see Authentication methods.

Connect as a superuser or RDS master user

Connect to the database you want to observe as a role that can CREATE ROLE — a superuser on self-managed PostgreSQL, or the master user on a managed service. Run the SQL below once per database cluster.

On Amazon RDS/Aurora, run this as your master user. It is not a full PostgreSQL superuser, but it is the role used for setup.

Create the read-only role

Run the following as a superuser (or the RDS master user), connected to the database you want to observe. The role is created NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS so it has no privileges beyond reading monitoring data:

-- Run as a superuser on each target database cluster.
CREATE ROLE signals LOGIN
    PASSWORD '<set-via-secret-store>'
    NOSUPERUSER
    NOCREATEDB
    NOCREATEROLE
    NOREPLICATION
    NOBYPASSRLS;

GRANT pg_monitor TO signals;

-- Allow it to connect to the database you want to observe.
GRANT CONNECT ON DATABASE your_database TO signals;

pg_monitor is a built-in PostgreSQL role (since 10) that aggregates the read-only monitoring sub-roles:

  • pg_read_all_settings — read all GUC values, including those marked as superuser-only.
  • pg_read_all_stats — read all pg_stat_* views regardless of the owning role.
  • pg_stat_scan_tables — execute monitoring functions that may take ACCESS SHARE locks.

This grant is read-only. It does not allow INSERT, UPDATE, DELETE, CREATE, schema changes, replication, or row-security bypass — only access to settings and the pg_stat_* statistics views. On managed services (Amazon RDS, Cloud SQL, Azure) you grant it the same way.

Verify the role

Verify by connecting as the signals role in a fresh psql session, using the same host, database, and TLS settings the daemon will use. On RDS/Aurora a SET ROLE test from the admin user is not a reliable check, so connect as the role itself:

psql "host=<host> port=5432 dbname=<dbname> user=signals \
  sslmode=verify-full sslrootcert=<ca-bundle.pem>"

Then, in that session, read should succeed and every write must fail:

-- Should succeed (read access to monitoring views):
SELECT count(*) FROM pg_stat_database;
SELECT count(*) FROM pg_stat_activity;

-- Should ALL fail with permission denied (no write / DDL / admin):
CREATE TABLE _signals_role_check (id int);
INSERT INTO pg_class VALUES (NULL);
SELECT pg_terminate_backend(1);
Do not expect a raw psql session as the role to report default_transaction_read_only = on. Signals enforces read-only at runtime on its own connections (it issues SET LOCAL default_transaction_read_only = on per transaction); a plain session does not set that, and it is not what makes the role safe — the privilege checks above are. See the read-only safety model.

To confirm what the role can actually do, audit it directly against the catalog:

SELECT rolname, rolsuper, rolinherit, rolcreaterole,
       rolcreatedb, rolcanlogin, rolreplication, rolbypassrls,
       (SELECT array_agg(b.rolname)
          FROM pg_auth_members m
          JOIN pg_roles b ON m.roleid = b.oid
         WHERE m.member = r.oid) AS memberships
  FROM pg_roles r
 WHERE rolname = 'signals';

Expected:

  • rolsuper, rolcreaterole, rolcreatedb, rolreplication, rolbypassrls are all f.
  • memberships includes pg_monitor and nothing that grants write access (pg_write_all_data is forbidden).

(Optional) Enable query statistics

pg_stat_statements adds query-level statistics. It is optional — Signals collects everything else without it, and the query-statistics collectors are skipped automatically rather than failing. The extension must be preloaded via shared_preload_libraries before it can be created:

  • Self-managed PostgreSQL: add pg_stat_statements to shared_preload_libraries in postgresql.conf, then restart the server.
  • RDS / Aurora: you do not edit postgresql.conf. In a custom DB parameter group, add pg_stat_statements to shared_preload_libraries, attach the group to the instance/cluster, and reboot if RDS marks the change pending-reboot.

Once the library is preloaded and the server has restarted, create the extension in the database you observe:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
Without pg_stat_statements installed, Signals still collects everything else; the query-statistics collectors are skipped automatically rather than failing.