Setting up pgblame with managed Postgres (RDS, Cloud SQL, Azure)
For AWS RDS, Google Cloud SQL, Azure Database for PostgreSQL, and similar managed Postgres services. The shape is identical; the provider differences are in where the parameter group lives.
1. Enable pg_stat_statements at the cluster level
On managed Postgres, pg_stat_statements requires adding it to shared_preload_libraries, which lives in the parameter group / flag config — not in SQL. This requires a database restart (usually 30–60 seconds of downtime).
AWS RDS / Aurora
- RDS console → Parameter groups. Make sure your instance uses a custom parameter group (the default is read-only).
- Edit it. Find
shared_preload_librariesand set it topg_stat_statements(or append it to existing values, comma-separated). - Apply to instance → Reboot (pending reboot is required for static parameters).
Google Cloud SQL
- Cloud SQL instance → Edit → Flags.
- Add flag
cloudsql.enable_pg_stat_statements=on. - Save. Cloud SQL restarts automatically.
Azure Database for PostgreSQL
- Server → Server parameters.
- Set
shared_preload_librariesto includepg_stat_statements. - Save. Restart the server.
Then, in any Postgres client
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;2. Create a read-only role
On RDS you cannot grant pg_read_all_stats directly because of the managed-superuser model. Use the provider-equivalent role:
-- Standard (Cloud SQL, Azure, self-hosted)
CREATE ROLE pgblame_reader WITH LOGIN PASSWORD '<strong-password>';
GRANT pg_read_all_stats TO pgblame_reader;
GRANT CONNECT ON DATABASE postgres TO pgblame_reader;
-- AWS RDS / Aurora alternative
CREATE ROLE pgblame_reader WITH LOGIN PASSWORD '<strong-password>';
GRANT rds_superuser TO pgblame_reader; -- if your master role has it
-- OR more narrowly:
GRANT pg_monitor TO pgblame_reader; -- includes pg_read_all_statspg_monitor is a standard built-in role that bundles pg_read_all_stats and is granted by master roles on RDS without needing superuser. Prefer it when available.
3. Network reachability
The agent must be able to reach your DB's host:port. Common patterns:
- RDS in a private subnet: run the agent on an EC2 instance / ECS task / Fargate / Lambda-on-EFS in the same VPC.
- Cloud SQL with Private IP: agent on GCE / GKE in the same VPC, or via the Cloud SQL Auth Proxy as a sidecar.
- Public endpoint with IP allowlist: add the agent host's public IP to the firewall / security group rule for
:5432.
The agent ships exactly one SELECT per minute; bandwidth and connection count are negligible.
4. Connection string
# RDS
postgresql://pgblame_reader:<password>@<endpoint>.<region>.rds.amazonaws.com:5432/postgres?sslmode=require
# Cloud SQL (via private IP or proxy)
postgresql://pgblame_reader:<password>@<private-ip>:5432/postgres?sslmode=require
# Azure
postgresql://pgblame_reader:<password>@<server>.postgres.database.azure.com:5432/postgres?sslmode=requireAlways use sslmode=require (or stricter) — managed providers terminate TLS at their edge.
5. Get a token and run the agent
In pgblame, create a project — the wizard tests the connection and issues a token. Then:
docker run -d \
--name pgblame-agent \
--restart unless-stopped \
-e PGBLAME_DATABASE_URL="postgresql://pgblame_reader:...@<host>:5432/postgres?sslmode=require" \
-e PGBLAME_TOKEN="pgb_xxxxxxxx" \
-v pgblame-data:/var/lib/pgblame \
ghcr.io/liberzon/pgblame-agent:latest6. Wire deploy webhooks
Troubleshooting
| Symptom | Likely cause |
|---|---|
pg_stat_statements does not exist | Parameter not yet applied — instance still rebooting, or you edited the default (read-only) parameter group. |
permission denied for function pg_stat_statements_reset | Harmless — the agent never resets stats. Ignore. |
could not translate host name | Agent can't resolve the DB endpoint — wrong VPC, missing VPC DNS, or typo. |
connection timed out | Security group / firewall not letting agent reach :5432. |
permission denied for view pg_stat_statements | Role missing pg_read_all_stats / pg_monitor. Re-grant. |