PGFlare connects to your AWS RDS PostgreSQL instance using a read-only IAM role. No software agents are installed on your infrastructure. This guide walks you through the exact steps required — for Windows, Bash/Linux, and macOS.
PGFlare uses the native AWS IAM authentication feature built into RDS PostgreSQL. This means:
| View / Source | Purpose |
|---|---|
| pg_stat_statements | Slow query detection, query fingerprinting, execution statistics |
| pg_stat_bgwriter | Checkpoint frequency, background writer efficiency |
| pg_stat_user_tables | Table bloat, autovacuum health, dead tuple ratios |
| pg_locks | Lock contention, blocking query detection |
| pg_stat_activity | Active connection count, idle-in-transaction sessions, wait events |
| pg_stat_replication | Replication lag monitoring (if applicable) |
| pg_indexes, pg_class | Index analysis, unused/duplicate index detection |
| AWS CloudWatch (RDS metrics) | CPU, memory, IOPS, FreeStorageSpace, DatabaseConnections |
Before starting, ensure you have:
postgres or
rdsadmin)
brew install awscli.
Linux: pip install awscli or use
your package manager.
IAM database authentication must be enabled on your RDS instance. If it is already enabled, skip to Step 2.
1. Open the RDS Console
2. Click Databases → select your instance → click Modify
3. Scroll to Database authentication
4. Select Password and IAM database authentication
5. Click Continue → choose Apply immediately → click Modify DB instance
# Replace these values
$Region = "eu-west-2"
$DBIdentifier = "your-rds-instance-id"
# Enable IAM authentication
aws rds modify-db-instance `
--db-instance-identifier $DBIdentifier `
--enable-iam-database-authentication `
--apply-immediately `
--region $Region
# Verify: check EnabledIAMDatabaseAuthentication is true
aws rds describe-db-instances `
--db-instance-identifier $DBIdentifier `
--region $Region `
--query "DBInstances[0].IAMDatabaseAuthenticationEnabled"
# Replace these values
REGION="eu-west-2"
DB_IDENTIFIER="your-rds-instance-id"
# Enable IAM authentication
aws rds modify-db-instance \
--db-instance-identifier "${DB_IDENTIFIER}" \
--enable-iam-database-authentication \
--apply-immediately \
--region "${REGION}"
# Verify (should return "true")
aws rds describe-db-instances \
--db-instance-identifier "${DB_IDENTIFIER}" \
--region "${REGION}" \
--query 'DBInstances[0].IAMDatabaseAuthenticationEnabled'
# Install AWS CLI (if not already installed)
brew install awscli
# Replace these values
REGION="eu-west-2"
DB_IDENTIFIER="your-rds-instance-id"
# Enable IAM authentication
aws rds modify-db-instance \
--db-instance-identifier "${DB_IDENTIFIER}" \
--enable-iam-database-authentication \
--apply-immediately \
--region "${REGION}"
# Verify (should return "true")
aws rds describe-db-instances \
--db-instance-identifier "${DB_IDENTIFIER}" \
--region "${REGION}" \
--query 'DBInstances[0].IAMDatabaseAuthenticationEnabled'
The RDS Resource ID is needed to scope the IAM policy to your specific instance (not all
instances in your account). It looks like db-ABCDEFGHIJKLMNOPQRSTUVWXYZ.
1. RDS Console → Databases → click your instance
2. On the Configuration tab, find Resource ID
3. Copy the value — it starts with db-
# Get the Resource ID (DbiResourceId)
aws rds describe-db-instances `
--db-instance-identifier $DBIdentifier `
--region $Region `
--query "DBInstances[0].DbiResourceId" `
--output text
# Save the output (e.g. db-ABCDE12345FGHIJ678KLM)
$DBResourceId = "db-REPLACE-WITH-ACTUAL-RESOURCE-ID"
# Get the Resource ID (DbiResourceId)
DB_RESOURCE_ID=$(aws rds describe-db-instances \
--db-instance-identifier "${DB_IDENTIFIER}" \
--region "${REGION}" \
--query 'DBInstances[0].DbiResourceId' \
--output text)
echo "Resource ID: ${DB_RESOURCE_ID}"
# Output: db-ABCDE12345FGHIJ678KLM
# Get the Resource ID (DbiResourceId)
DB_RESOURCE_ID=$(aws rds describe-db-instances \
--db-instance-identifier "${DB_IDENTIFIER}" \
--region "${REGION}" \
--query 'DBInstances[0].DbiResourceId' \
--output text)
echo "Resource ID: ${DB_RESOURCE_ID}"
# Output: db-ABCDE12345FGHIJ678KLM
This policy grants PGFlare the minimum required permissions: connect to your RDS instance via IAM auth, describe instances, and read CloudWatch metrics for your RDS resources.
1. Open IAM Console → Policies → Create policy
2. Click the JSON tab and paste the policy below
3. Replace the placeholder values in the Resource ARN
4. Click Next → name it PGFlareMonitorPolicy
→ Create policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PGFlareIAMConnect",
"Effect": "Allow",
"Action": "rds-db:connect",
"Resource": "arn:aws:rds-db:REGION:ACCOUNT_ID:dbuser:DB_RESOURCE_ID/pgflare_monitor"
},
{
"Sid": "PGFlareDescribeRDS",
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances",
"rds:DescribeDBParameters",
"rds:ListTagsForResource"
],
"Resource": "*"
},
{
"Sid": "PGFlareCloudWatch",
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricData",
"cloudwatch:GetMetricStatistics",
"cloudwatch:ListMetrics"
],
"Resource": "*"
}
]
}
# Replace these values
$AccountId = "123456789012"
$Region = "eu-west-2"
$DBResourceId = "db-REPLACE-WITH-ACTUAL-RESOURCE-ID"
# Build the policy JSON
$PolicyJson = @"
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PGFlareIAMConnect",
"Effect": "Allow",
"Action": "rds-db:connect",
"Resource": "arn:aws:rds-db:${Region}:${AccountId}:dbuser:${DBResourceId}/pgflare_monitor"
},
{
"Sid": "PGFlareDescribeRDS",
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances",
"rds:DescribeDBParameters",
"rds:ListTagsForResource"
],
"Resource": "*"
},
{
"Sid": "PGFlareCloudWatch",
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricData",
"cloudwatch:GetMetricStatistics",
"cloudwatch:ListMetrics"
],
"Resource": "*"
}
]
}
"@
# Save to temp file (Windows requires a file path for --policy-document)
$PolicyJson | Out-File -FilePath "pgflare-policy.json" -Encoding UTF8
# Create the policy
aws iam create-policy `
--policy-name "PGFlareMonitorPolicy" `
--policy-document "file://pgflare-policy.json"
# Note the PolicyArn in the output — you need it in Step 4
# Replace these values
ACCOUNT_ID="123456789012"
REGION="eu-west-2"
DB_RESOURCE_ID="db-REPLACE-WITH-ACTUAL-RESOURCE-ID"
# Create the policy JSON file
cat > pgflare-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PGFlareIAMConnect",
"Effect": "Allow",
"Action": "rds-db:connect",
"Resource": "arn:aws:rds-db:${REGION}:${ACCOUNT_ID}:dbuser:${DB_RESOURCE_ID}/pgflare_monitor"
},
{
"Sid": "PGFlareDescribeRDS",
"Effect": "Allow",
"Action": ["rds:DescribeDBInstances", "rds:DescribeDBParameters", "rds:ListTagsForResource"],
"Resource": "*"
},
{
"Sid": "PGFlareCloudWatch",
"Effect": "Allow",
"Action": ["cloudwatch:GetMetricData", "cloudwatch:GetMetricStatistics", "cloudwatch:ListMetrics"],
"Resource": "*"
}
]
}
EOF
# Create the policy
aws iam create-policy \
--policy-name "PGFlareMonitorPolicy" \
--policy-document "file://pgflare-policy.json"
# Note the PolicyArn in the output — you need it in Step 4
# Replace these values
ACCOUNT_ID="123456789012"
REGION="eu-west-2"
DB_RESOURCE_ID="db-REPLACE-WITH-ACTUAL-RESOURCE-ID"
# Create the policy JSON file
cat > pgflare-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PGFlareIAMConnect",
"Effect": "Allow",
"Action": "rds-db:connect",
"Resource": "arn:aws:rds-db:${REGION}:${ACCOUNT_ID}:dbuser:${DB_RESOURCE_ID}/pgflare_monitor"
},
{
"Sid": "PGFlareDescribeRDS",
"Effect": "Allow",
"Action": ["rds:DescribeDBInstances", "rds:DescribeDBParameters", "rds:ListTagsForResource"],
"Resource": "*"
},
{
"Sid": "PGFlareCloudWatch",
"Effect": "Allow",
"Action": ["cloudwatch:GetMetricData", "cloudwatch:GetMetricStatistics", "cloudwatch:ListMetrics"],
"Resource": "*"
}
]
}
EOF
# Create the policy
aws iam create-policy \
--policy-name "PGFlareMonitorPolicy" \
--policy-document "file://pgflare-policy.json"
Create a role that trusts PGFlare's AWS account, and attach the policy from Step 3. PGFlare will assume this role to connect — you grant access, we cannot exceed the permissions you define here.
1. IAM Console → Roles → Create role
2. Select AWS account → choose Another AWS account
3. Enter the Account ID provided in your PGFlare onboarding email
4. Click Next → in the search box, find and select PGFlareMonitorPolicy
5. Click Next → name the role pgflare-monitor-role
6. Click Create role
7. Click into the new role and copy the Role ARN — you'll share this with PGFlare
# Replace with PGFlare's account ID (provided in your onboarding email)
$PGFlareAccountId = "PGFLARE_ACCOUNT_ID"
$PolicyArn = "arn:aws:iam::${AccountId}:policy/PGFlareMonitorPolicy"
# Trust policy — allows PGFlare's AWS account to assume this role
$TrustPolicy = @"
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${PGFlareAccountId}:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "PGFLARE_EXTERNAL_ID"
}
}
}]
}
"@
$TrustPolicy | Out-File -FilePath "pgflare-trust.json" -Encoding UTF8
# Create the role
aws iam create-role `
--role-name "pgflare-monitor-role" `
--assume-role-policy-document "file://pgflare-trust.json"
# Attach the policy
aws iam attach-role-policy `
--role-name "pgflare-monitor-role" `
--policy-arn $PolicyArn
# Get the Role ARN — copy this and share it with PGFlare
aws iam get-role `
--role-name "pgflare-monitor-role" `
--query "Role.Arn" `
--output text
# Replace with PGFlare's account ID (provided in your onboarding email)
PGFLARE_ACCOUNT_ID="PGFLARE_ACCOUNT_ID"
POLICY_ARN="arn:aws:iam::${ACCOUNT_ID}:policy/PGFlareMonitorPolicy"
# Create trust policy
cat > pgflare-trust.json << EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::${PGFLARE_ACCOUNT_ID}:root" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "sts:ExternalId": "PGFLARE_EXTERNAL_ID" }
}
}]
}
EOF
# Create the role
aws iam create-role \
--role-name "pgflare-monitor-role" \
--assume-role-policy-document "file://pgflare-trust.json"
# Attach the policy
aws iam attach-role-policy \
--role-name "pgflare-monitor-role" \
--policy-arn "${POLICY_ARN}"
# Get and display the Role ARN — copy this and share with PGFlare
aws iam get-role \
--role-name "pgflare-monitor-role" \
--query 'Role.Arn' \
--output text
# Same as Bash — macOS Terminal supports these commands natively
PGFLARE_ACCOUNT_ID="PGFLARE_ACCOUNT_ID"
POLICY_ARN="arn:aws:iam::${ACCOUNT_ID}:policy/PGFlareMonitorPolicy"
cat > pgflare-trust.json << EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::${PGFLARE_ACCOUNT_ID}:root" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "sts:ExternalId": "PGFLARE_EXTERNAL_ID" }
}
}]
}
EOF
aws iam create-role \
--role-name "pgflare-monitor-role" \
--assume-role-policy-document "file://pgflare-trust.json"
aws iam attach-role-policy \
--role-name "pgflare-monitor-role" \
--policy-arn "${POLICY_ARN}"
# Copy the output — share it with PGFlare
aws iam get-role \
--role-name "pgflare-monitor-role" \
--query 'Role.Arn' \
--output text
Connect to your RDS instance as the master user (e.g. postgres)
and run the following SQL. This creates a passwordless user that authenticates via IAM token,
then grants it read-only access to the performance views PGFlare requires.
rds_superuser to grant rds_iam. The pgflare_monitor user will
have no ability to read application tables.
-- Step 5a: Enable pg_stat_statements extension (if not already enabled)
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- Step 5b: Create the monitoring user (no password — uses IAM auth)
CREATE USER pgflare_monitor;
-- Step 5c: Grant IAM authentication to the user (RDS-specific)
GRANT rds_iam TO pgflare_monitor;
-- Step 5d: Grant the built-in pg_monitor role (read-only system stats)
-- Grants access to pg_stat_activity, pg_stat_bgwriter, pg_locks
-- and all pg_stat_* views without accessing application data
GRANT pg_monitor TO pgflare_monitor;
-- Step 5e: Grant access to pg_stat_statements specifically
GRANT SELECT ON pg_stat_statements TO pgflare_monitor;
GRANT SELECT ON pg_stat_statements_info TO pgflare_monitor;
-- Step 5f: Verify the user was created correctly
SELECT
usename,
usesuper,
usecreatedb,
usecreaterole,
usebypassrls
FROM pg_user
WHERE usename = 'pgflare_monitor';
-- Expected output:
-- usename | usesuper | usecreatedb | usecreaterole | usebypassrls
-- -----------------+----------+-------------+---------------+--------------
-- pgflare_monitor | f | f | f | f
-- (all false — no elevated privileges)
f (false). PGFlare's user has
no superuser, no DB creation, no role creation, and no bypass RLS capability. It is read-only.
Email the following details to hello@pgflare.com with the subject line "RDS Onboarding — [Your Company Name]". We'll have monitoring active within 4 hours of receipt.
Once PGFlare confirms the connection is active, you can verify the monitoring user is connecting
correctly by checking pg_stat_activity:
-- Check for active PGFlare connections
SELECT
usename,
application_name,
client_addr,
state,
backend_start
FROM pg_stat_activity
WHERE usename = 'pgflare_monitor'
ORDER BY backend_start DESC;
-- If PGFlare is connected, you will see one row.
-- application_name will be 'pgflare'
-- state will be 'idle' (we connect, collect, and disconnect)
To instantly revoke PGFlare's access, you can do either of the following — no PGFlare involvement required:
PGFlareMonitorPolicy
from the role — access is revoked immediatelypgflare-monitor-role
from IAM — all subsequent connection attempts will failREVOKE rds_iam FROM pgflare_monitor; DROP USER pgflare_monitor;
You remain in complete control of access at all times.