pgblame

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_libraries and set it to pg_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 → EditFlags.
  • Add flag cloudsql.enable_pg_stat_statements = on.
  • Save. Cloud SQL restarts automatically.

Azure Database for PostgreSQL

  • Server → Server parameters.
  • Set shared_preload_libraries to include pg_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_stats

pg_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=require

Always 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:latest

6. Wire deploy webhooks

Troubleshooting

SymptomLikely cause
pg_stat_statements does not existParameter not yet applied — instance still rebooting, or you edited the default (read-only) parameter group.
permission denied for function pg_stat_statements_resetHarmless — the agent never resets stats. Ignore.
could not translate host nameAgent can't resolve the DB endpoint — wrong VPC, missing VPC DNS, or typo.
connection timed outSecurity group / firewall not letting agent reach :5432.
permission denied for view pg_stat_statementsRole missing pg_read_all_stats / pg_monitor. Re-grant.