Skill

PostgreSQL

postgresql · current version v1

Download v1

Troubleshoot and support a PostgreSQL server — connect, diagnose, and resolve problems across 13/14/15/16/17, on Docker, bare metal, systemd, a managed service, or Kubernetes. Covers psql, pg_isready, config and hba files, connections, locks, slow queries, autovacuum/bloat, replication, WAL/disk, and a pgvector section. Use when someone reports Postgres is down, slow, refusing connections, out of disk, deadlocking, bloated, lagging a replica, or when a pgvector query is slow or wrong.

16 downloads · published 2026-09-02

What this grants

Skill Card

Security Audits

Version history

VersionPublishedStatus
v1 2026-09-02 published

Files

SKILL.md

raw | preview

PostgreSQL — Troubleshooting & Support

A support runbook, not a tutorial. Establish the host first with the detect-platform skill, then work top to bottom: read before you write, and treat every mutating step as deliberate. Commands and output below were run against PostgreSQL 17.11.

Current majors are 13–17 (17 is newest; a major is EOL ~5 years after release — 12 is out, confirm at https://www.postgresql.org/support/versioning/). Postgres numbers one major per year; the ".x" is a patch level, not a feature change.

0. Identify what you are on

psql --version                                   # psql (PostgreSQL) 17.11
psql -U postgres -tAc 'select version();'        # server version — may differ from the client
psql -U postgres -tAc 'show server_version_num;' # e.g. 170011, easy to compare

Where its files and state are (ground truth, not a guess):

psql -U postgres -tAc 'SHOW config_file;'    # /var/lib/postgresql/data/postgresql.conf (in the image)
psql -U postgres -tAc 'SHOW hba_file;'       # pg_hba.conf — who may connect, from where, how
psql -U postgres -tAc 'SHOW data_directory;' # the PGDATA
pg_isready -U postgres                        # "accepting connections" | "no response" | "rejecting"

1. Connect, per deployment

Docker — logs go to stderr → docker logs (logging_collector is off, confirmed):

docker exec -it <c> psql -U postgres
docker logs --tail 200 -f <c>

systemd (bare metal or VM):

systemctl status postgresql        # Debian: postgresql@<ver>-main ; RHEL: postgresql-<ver>
journalctl -u postgresql -n 200 --no-pager
sudo -u postgres psql              # peer auth as the postgres OS user
# Debian PGDATA: /var/lib/postgresql/<ver>/main ; conf under /etc/postgresql/<ver>/main/

Bare metal — the host settings Postgres cares about (detect-platform found the substrate):

cat /proc/sys/kernel/shmmax 2>/dev/null        # SysV shm (mostly historical; PG uses mmap now)
cat /sys/kernel/mm/transparent_hugepage/enabled   # THP=always can cause latency; prefer disabled
free -h                                         # shared_buffers ~25% RAM is a starting point, not a law
# a cgroup memory cap below what shared_buffers+work_mem*connections assumes => OOM (detect-platform)

Managed — no host shell; psql connects, config is the provider's parameter group, and the console owns restarts/failover/upgrades. pg_stat_* views and logs (via the console) still work.

Kubernetes (operator) — kubectl exec -it <pod> -- psql -U postgres; config is the CR, not a file on the pod; the superuser password is in a Secret.

2. Tools and arguments

psql -h <host> -p 5432 -U <user> -d <db>       # -tAc for one clean scalar; -f file.sql to run a script
pg_isready -h <host> -U <user>                 # liveness without logging in
pg_dump -Fc -d <db> -f db.dump                 # -Fc custom format; restore with pg_restore
pg_restore -d <db> --clean --if-exists db.dump
pg_dumpall --globals-only                      # roles + tablespaces (not in a per-db pg_dump)
pg_basebackup -h <primary> -D <dir> -X stream  # base backup for a new replica

Useful psql meta-commands: \l databases, \dt+ tables with size, \dx extensions, \du roles, \d <table>, \di+ indexes, \timing on.

3. Diagnostics — read-only first

SELECT count(*), state FROM pg_stat_activity GROUP BY state;   -- active/idle/idle in transaction
SELECT pid, now()-query_start AS run, state, wait_event_type, left(query,80)
  FROM pg_stat_activity WHERE state<>'idle' ORDER BY run DESC;  -- the long-runners
SELECT * FROM pg_stat_activity WHERE wait_event_type='Lock';    -- who is blocked
SELECT bl.pid AS blocked, ka.pid AS blocking, left(ka.query,60) AS blocking_q
  FROM pg_locks bl JOIN pg_stat_activity a ON a.pid=bl.pid
  JOIN pg_locks kl ON kl.locktype=bl.locktype AND kl.pid<>bl.pid AND NOT kl.granted=false
  JOIN pg_stat_activity ka ON ka.pid=kl.pid WHERE NOT bl.granted;  -- blocked/blocking pairs
SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database ORDER BY 2 DESC;
SELECT schemaname, relname, n_dead_tup, last_autovacuum FROM pg_stat_user_tables
  ORDER BY n_dead_tup DESC LIMIT 10;            -- bloat / autovacuum keeping up?

Slow queries: enable log_min_duration_statement = 200 (ms) or install pg_stat_statements and SELECT query, calls, mean_exec_time FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10; Plans: EXPLAIN (ANALYZE, BUFFERS) <query>; — look for Seq Scan on a big table, and rows estimated ≫ actual (stale stats → ANALYZE).

4. Common problems → resolution

Cannot connect

"Too many connections" / idle in transaction

Disk filling

Deadlocks / blocking

Replication lag / replica not catching up

-- on the primary:
SELECT client_addr, state, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) AS lag
  FROM pg_stat_replication;
-- on the replica:
SELECT now()-pg_last_xact_replay_timestamp() AS replay_delay;

Lag is usually the replica's disk/CPU, or a long query on the replica holding replay (max_standby_streaming_delay). A replica that fell off entirely and lost its slot needs a fresh pg_basebackup.

Autovacuum "not running" It is, but may be outrun by write volume or blocked by a long transaction / idle-in-transaction holding an old xmin. Check SELECT max(age(datfrozenxid)) FROM pg_database; — a large, rising value warns of wraparound, which is an emergency (Postgres will refuse writes to protect data).

5. pgvector (the vector extension)

pgvector is a Postgres extension, not a separate server — everything above still applies; this is only what is specific to it. Verified: extension version 0.8.6 on PG 17.

CREATE EXTENSION IF NOT EXISTS vector;                 -- must run in EACH database that needs it
SELECT extname, extversion FROM pg_extension WHERE extname='vector';   -- vector 0.8.6
\dx                                                    -- confirm it is installed

The problems that are actually pgvector

6. Before you run anything that writes

Config changes, VACUUM FULL, terminating backends, dropping slots, and restarts change data, availability, or config, and on a nanoinfra deployment resolve to a mutate.remote capability — approval interactively, a standing grant unattended.