The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Lock rows in key orderSELECT id FROM app.accounts WHERE id = ANY (ARRAY[41,72]) ORDER BY id FOR UPDATE;View examples
Lock a table explicitlyLOCK TABLE app.ledger IN SHARE ROW EXCLUSIVE MODE;View examples
Inspect deadlock delaySHOW deadlock_timeout;View examples
Set transaction-local lock timeoutSET LOCAL lock_timeout = '2s';View examples
Disable the lock timeoutSET LOCAL lock_timeout = '0';View examples
Set a statement timeoutSET LOCAL statement_timeout = '30s';View examples
Set a role defaultALTER ROLE report_user SET statement_timeout = '30s';View examples
Inspect the timeoutSHOW statement_timeout;View examples
Bound idle transactionsSET idle_in_transaction_session_timeout = '60s';View examples
Bound a transactionSET transaction_timeout = '5min';View examples
Find blocking PIDsSELECT pg_blocking_pids(12345);View examples
List lock waitersSELECT pid, wait_event, query FROM pg_stat_activity WHERE wait_event_type = 'Lock';View examples
Inspect held locksSELECT * FROM pg_locks WHERE pid = 12345;View examples
Cancel a backend querySELECT pg_cancel_backend(12345);View examples
Terminate a backendSELECT pg_terminate_backend(12345, 5000);View examples
Inspect lock-wait loggingSHOW log_lock_waits;View examples
Inspect active transaction ageSELECT pid, xact_start, state FROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY xact_start;View examples

PostgreSQL detects true deadlocks and aborts one participant, but ordinary blocking can wait indefinitely unless applications set explicit budgets. Reliable systems acquire resources consistently, keep transactions short, distinguish statement cancellation from session termination, and retry only whole idempotent transactions.

Step by step

Detailed examples

01

Acquire resources in a consistent order

Deadlocks arise from cycles of incompatible locks, including row, table, advisory, and transaction-ID waits. PostgreSQL chooses one transaction as the victim; applications should avoid cycles by sorting keys and acquiring the strongest needed locks consistently. A retry must replay the entire transaction because its prior work was rolled back.

Lock account rows in deterministic order
BEGIN;
SELECT id FROM app.accounts
WHERE id IN (41, 72)
ORDER BY id
FOR UPDATE;
UPDATE app.accounts SET balance = balance - 100 WHERE id = 41;
UPDATE app.accounts SET balance = balance + 100 WHERE id = 72;
COMMIT;

Note: All code paths touching these accounts must use the same ordering for the convention to work.

Back to quick reference ↑
02

Bound time spent waiting for locks

lock_timeout applies only while acquiring a lock, not while executing afterward. A zero value disables it. Set it below statement_timeout when both are used, otherwise the broader statement timeout usually fires first and the lock-specific signal adds no value.

Give a migration a short lock-acquisition budget
BEGIN;
SET LOCAL lock_timeout = '2s';
ALTER TABLE app.orders ADD COLUMN fulfilled_at timestamptz;
COMMIT;

Note: Failure cancels the statement and leaves the transaction aborted; rollback and reschedule rather than looping aggressively.

Back to quick reference ↑
03

Give server statements an execution budget

statement_timeout measures from command arrival until completion; in extended-query protocol it applies per query-related message. A timeout cancels the current statement, not the connection. Setting it globally in postgresql.conf can disrupt maintenance and replication roles, so prefer role, database, or transaction scopes.

Bound one reporting transaction
BEGIN READ ONLY;
SET LOCAL statement_timeout = '30s';
SELECT tenant_id, sum(total) FROM app.orders GROUP BY tenant_id;
COMMIT;
Back to quick reference ↑
04

Terminate abandoned transactions and sessions

idle_in_transaction_session_timeout ends sessions that sit idle inside a transaction, releasing locks and preventing vacuum horizons from being pinned. idle_session_timeout targets sessions outside a transaction but may interact poorly with poolers. PostgreSQL 18 transaction_timeout bounds a transaction from its start; if it is shorter than or equal to statement_timeout or idle_in_transaction_session_timeout, PostgreSQL ignores that longer timeout. Prepared transactions are exempt.

Protect an application role from forgotten transactions
ALTER ROLE app_user SET idle_in_transaction_session_timeout = '60s';
ALTER ROLE app_user SET transaction_timeout = '5min';

Note: Test pool behavior first; settings affect new sessions and termination discards session state.

Back to quick reference ↑
05

Build wait graphs from supported monitoring functions

pg_stat_activity shows current activity and wait events; pg_blocking_pids returns sessions blocking a PID, including prepared transactions represented by zero. Repeatedly querying the views gives only snapshots. Access to other sessions query text is restricted unless the role has suitable monitoring privileges.

List blocked sessions and their blockers
SELECT a.pid, a.usename, a.wait_event_type, a.wait_event,
       pg_blocking_pids(a.pid) AS blocking_pids,
       clock_timestamp() - a.query_start AS query_age, a.query
FROM pg_stat_activity a
WHERE cardinality(pg_blocking_pids(a.pid)) > 0
ORDER BY a.query_start;
Back to quick reference ↑
06

Cancel work before terminating a session

pg_cancel_backend requests cancellation of the current query while preserving the connection; pg_terminate_backend ends the session and rolls back its transaction. The caller must own the target role, be a member of it, or hold pg_signal_backend, while only superusers may signal superuser backends. Verify PID, user, database, query, and age immediately before acting because PIDs are reusable.

Generate a reviewed cancellation decision
SELECT pid, usename, datname, state, query_start, query
FROM pg_stat_activity
WHERE pid = 12345;
-- After human verification: SELECT pg_cancel_backend(12345);

Note: Do not automate termination from stale PID lists; cancel first unless an incident runbook requires stronger action.

Back to quick reference ↑
07

Capture evidence and retry only safe transaction units

log_lock_waits records waits that exceed deadlock_timeout and log_min_error_statement can preserve failed SQL, subject to sensitive-data policies. SQLSTATE 40P01 identifies deadlock_detected and 40001 identifies serialization_failure; retry with bounded exponential jitter only when the whole transaction is safe to repeat. Timeouts and user cancellation use different error states and may represent overload, not transient serialization.

Expose lock waits during a diagnostic window
SELECT name, setting, unit, source
FROM pg_settings
WHERE name IN ('log_lock_waits', 'deadlock_timeout', 'log_min_error_statement')
ORDER BY name;

Note: Change logging through approved configuration management; query text can contain sensitive values.

Back to quick reference ↑

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. PostgreSQL Global Development GroupExplicit Lockingpostgresql.org
  2. PostgreSQL Global Development GroupClient Connection Defaultspostgresql.org
  3. PostgreSQL Global Development GroupLock Managementpostgresql.org
  4. PostgreSQL Global Development GroupMonitoring Database Activitypostgresql.org
  5. PostgreSQL Global Development Grouppg_lockspostgresql.org
  6. PostgreSQL Global Development GroupSystem Information Functionspostgresql.org
  7. PostgreSQL Global Development GroupSystem Administration Functionspostgresql.org
  8. PostgreSQL Global Development GroupPostgreSQL Error Codespostgresql.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback