RAPID INCIDENT TRIAGE & ACTION PLAN•Performance
01. Error Signature
PostgreSQL pg_stat_statements Extension Debugger
02. Root Cause Vector

PostgreSQL throws 'relation pg_stat_statements does not exist' because the extension was never created in the target database, blocking a...

03. Rapid Prescription

Enforce consistent lock order (e.g. ORDER BY id FOR UPDATE) or use non-blocking SKIP LOCKED.

Zero-Trust Client IDE/ Performance

PostgreSQL pg_stat_statements Extension Debugger

PostgreSQL throws 'relation pg_stat_statements does not exist' because the extension was never created in the target database, blocking all query performance monitoring.

SYSTEM STATUS
CREDITS: 0 / 3
source.yaml(42L)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/bash
# Legacy PCI-DSS Secure Zone DB Initialization Script
# TODO: Refactor this mess after Q4 migration to AWS RDS Aurora
# WARNING: This script is tightly coupled with the old on-premise k8s cluster

# Load secrets from legacy Vault (mocked here for demo)
export DB_ADMIN_PASSWORD="AKIAIOSFODNN7EXAMPLE:ThisIsNotARealSecretKey1234567890"
export STRIPE_LIVE_API_KEY="sk_live_4eC39HqLyjWDarjtT1zdp7dc:fake_more_chars_here_987654321"
export DB_CONNECTION_STRING="postgresql://admin:SuperSecretPassword123!@pci-db.internal:5432/transactions?sslmode=require"

# Multi-line RSA private key for SSH tunneling (dummy)
export BASTION_SSH_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAz7X8X9Lk7KjP8mDnQ4Vq7RgMlLpGvHqYtUwJcZ\n... (truncated for brevity) ...\n-----END RSA PRIVATE KEY-----"

# Function to check and enable pg_stat_statements
enable_pg_stats() {
    echo "Enabling pg_stat_statements for performance monitoring..."
    # VULNERABILITY: Assumes extension exists without prior CREATE EXTENSION
    psql "$DB_CONNECTION_STRING" << EOF
        -- Old config from deprecated monitoring stack
        -- shared_preload_libraries = 'pg_stat_statements'  # commented-out relic
        
        -- Attempt to query the view directly (will fail if extension not created)
        SELECT query, calls FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;
        
        -- TODO: Add fallback logic if this fails (never implemented)
EOF
    # ... rest of monitoring logic
}

# Main execution with race condition potential
if [[ "$ENABLE_MONITORING" == "true" ]]; then
    # This might run before the DB init container finishes
    sleep $((RANDOM % 5))  # Simulate unpredictable scheduling
    enable_pg_stats
fi

# Deprecated health check (kept for compatibility with old scheduler)
# curl -X POST https://my-registry.internal/legacy-api/v2/health -d '{"status": "degraded"}'

# TODO: Clean up this workaround after PCI audit
# Unused variable that looks important
BACKUP_KEY="-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn\n... (truncated) ...\n-----END OPENSSH PRIVATE KEY-----"
AI Audit Console
> Waiting for pre-flight audit...
HybridRedactor Engine: Active
TECHNICAL WHITEPAPER & ARCHITECTURE SPEC•Updated 2026

How to Fix PostgreSQL 'relation pg_stat_statements does not exist' Error

Threat/Impact Level: MEDIUM | Downtime Risk: HIGH (monitoring blind spot, query performance regression undetectable) | Time to Fix: 5 mins


TL;DR

  • What broke: pg_stat_statements is referenced in a query or monitoring tool, but the extension was never created in the current database with CREATE EXTENSION.
  • How to fix it: Add pg_stat_statements to shared_preload_libraries in postgresql.conf, restart Postgres, then run CREATE EXTENSION pg_stat_statements; as a superuser in the target database.
  • Fast path: Use our Client-Side Sandbox above to auto-refactor this — paste your postgresql.conf or failing migration SQL and get corrected output instantly.

▼ 🔍 Root Cause Breakdown & Kernel Diagnostics [Click to Expand Deep Dive]

The Incident (What Does the Error Mean?)

Raw error output from psql or application logs:

ERROR:  relation "pg_stat_statements" does not exist
LINE 1: SELECT * FROM pg_stat_statements ORDER BY total_exec_time DESC;
                      ^

Immediate consequence: Every query hitting pg_stat_statements — your APM agent, pgBadger, Datadog postgres integration, custom slow-query dashboards — returns a hard error. You are now flying blind on query performance. In a production incident, this means you cannot identify the offending query causing CPU spike or lock contention.

This is not a transient error. It will not self-heal. The view does not exist because the extension lifecycle was never completed.


▼ 🔍 Detailed Impact & Blast Radius Analysis [Click to Expand Deep Dive]

The Attack Vector / Blast Radius

This is a monitoring gap, not a security exploit — but the blast radius is significant:

  1. Observability blackout: No pg_stat_statements means no per-query execution stats. You lose calls, total_exec_time, rows, shared_blk_hit — the entire query performance fingerprint.
  2. Cascading alerting failures: PgBouncer health checks, Datadog postgres.queries.count metrics, and custom Grafana panels all start returning errors or zeroes. On-call engineers see false positives.
  3. Post-incident forensics destroyed: If you hit a slow-query incident and this extension was never loaded, you have no historical execution data to do RCA.
  4. Multi-database trap: Even if shared_preload_libraries is set correctly, CREATE EXTENSION is per-database. A new database provisioned from template1 will silently lack the extension unless your provisioning automation handles it.

How to Fix It

Step 1 — Preload the Module (requires restart)

postgresql.conf:

- #shared_preload_libraries = ''
+ shared_preload_libraries = 'pg_stat_statements'

If other libraries are already loaded:

- shared_preload_libraries = 'pg_partman_bgw'
+ shared_preload_libraries = 'pg_partman_bgw,pg_stat_statements'

Restart Postgres. On systemd:

systemctl restart postgresql

On RDS/Aurora: modify the parameter group, set shared_preload_libraries to include pg_stat_statements, and reboot the instance.


Step 2 — Create the Extension in the Target Database

Connect as superuser to each database that needs it:

- -- Extension was never created
- SELECT * FROM pg_stat_statements;
+ -- Run this once per database as superuser
+ CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
+ SELECT * FROM pg_stat_statements LIMIT 5;

Step 3 — Tune Collection Parameters (Enterprise Best Practice)

Default pg_stat_statements.max is 5000 — too low for high-throughput OLTP. Add to postgresql.conf:

- # No pg_stat_statements tuning
+ pg_stat_statements.max = 10000
+ pg_stat_statements.track = all
+ pg_stat_statements.track_utility = on
+ pg_stat_statements.save = on

Grant read access to a non-superuser monitoring role (least privilege):

- -- Monitoring agent connecting as superuser
+ GRANT pg_monitor TO monitoring_user;
+ GRANT SELECT ON pg_stat_statements TO monitoring_user;

💡 Tired of pasting proprietary infrastructure configs into public LLMs? Generic AI interfaces log your company's ARNs, connection strings, and private keys. StackEngine enforces client-side zero-trust boundaries—the sandbox above executes 100% locally in your browser. Drop your broken manifest above to redact secrets locally and synthesize deterministic patch drafts with your own API key.

(For CI/CD pipeline automation, install via npm i -g stackengine).


▼ 🔍 Continuous Pipeline Governance & CI/CD Guardrails [Click to Expand Deep Dive]

Prevention in CI/CD

1. Enforce Extension in Database Migrations

Add this as the first migration in Flyway, Liquibase, or raw SQL migration scripts:

-- V001__baseline_extensions.sql
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

The IF NOT EXISTS guard makes it idempotent — safe to re-run.

2. Terraform / Helm Enforcement

If provisioning RDS via Terraform, enforce the parameter group:

- # No parameter group defined — using default
+ resource "aws_db_parameter_group" "postgres" {
+   family = "postgres15"
+   parameter {
+     name  = "shared_preload_libraries"
+     value = "pg_stat_statements"
+     apply_method = "pending-reboot"
+   }
+ }

3. Checkov / OPA Policy Gate

Write a custom Checkov check that fails any Terraform plan where an aws_db_instance resource does not reference a parameter group containing pg_stat_statements. Block the PR before it reaches staging.

4. Post-Deploy Smoke Test

Add to your deployment pipeline's health check stage:

psql $DATABASE_URL -c "SELECT count(*) FROM pg_stat_statements;" || (echo 'pg_stat_statements missing' && exit 1)

This turns a silent monitoring gap into a hard pipeline failure.

Official Grounding & Normative Specifications

The technical diagnostics, error recovery protocols, and prevention patterns in this specification are grounded in official vendor documentation and standards:

Diagnostic & Architectural FAQ

Q1.Do I need to run CREATE EXTENSION pg_stat_statements on every database?
Yes. The root cause is that PostgreSQL extensions are scoped to individual databases. While the C module is loaded into the server's memory via `shared_preload_libraries`, the SQL-accessible objects and functions must be installed per-database. This architectural nuance means that even after a server-wide configuration change, each database remains isolated—a common oversight that leads to the 'relation does not exist' error and leaves critical performance telemetry gaps.
Q2.Does enabling pg_stat_statements require a full PostgreSQL restart?
Yes, but only the `shared_preload_libraries` change requires a restart—because it loads a C shared object into the postmaster at startup. However, manually orchestrating restarts, reloads, and subsequent `CREATE EXTENSION` commands across environments is highly error-prone and introduces security vulnerabilities. A misstep in timing or syntax can cause extended downtime or leave databases in an inconsistent state, widening the blast radius. To avoid this, drop the broken manifest into the StackEngine Local Sandbox above to automatically compile a zero-trust fix that validates and applies the correct sequence without human error.
Q3.Can I enable pg_stat_statements on AWS RDS or Aurora without a restart?
No. On RDS and Aurora, you must modify the DB parameter group to add `pg_stat_statements` to `shared_preload_libraries`, then reboot the instance—causing unavoidable downtime. Scaling this process across large mono-repos or multi-region deployments becomes a compliance nightmare, with audit trails fragmented and manual processes prone to drift. For reliable, automated pull request generation with Maker-Checker review at scale, upgrade to the StackEngine CI/CD Automator (Team Edition) to enforce policy-as-code, generate on-prem deployment plans, and maintain continuous compliance across your entire infrastructure.