Multiple queries are waiting for the same lock — pg_stat_activity shows a chain of blocked sessions, and application latency is rising.
Diagnose it
Use the built-in pg_blocking_pids() function (available since PostgreSQL 9.6)
together with pg_locks to map the full blocking chain:
-- Blocked sessions and their blockers:
SELECT blocked.pid AS blocked_pid,
blocked.usename AS blocked_user,
blocked.application_name,
LEFT(blocked.query, 100) AS blocked_query,
blocked.wait_event_type,
blocked.wait_event,
blocking.pid AS blocking_pid,
blocking.usename AS blocking_user,
LEFT(blocking.query, 100) AS blocking_query,
blocking.state AS blocking_state
FROM pg_stat_activity AS blocked
JOIN pg_stat_activity AS blocking
ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
WHERE pg_blocking_pids(blocked.pid) <> '{}'
ORDER BY blocked.pid;
-- Lock detail for the blocking backend:
SELECT pid, locktype, relation::regclass, mode, granted,
waitstart
FROM pg_locks
WHERE pid = <blocking_pid>
ORDER BY granted DESC;
Why it happens
Every DML statement (and many DDL statements) acquires a lock on affected rows and tables.
If two transactions need conflicting lock modes on the same object, the later one waits.
A long-running transaction holding a table-level or row lock can cause a queue of waiters
to grow, eventually stalling the application entirely.