Module A-13·25 min read

Concurrency bugs are almost never about wrong SQL — they are about wrong locking assumptions. The complete PostgreSQL locking matrix.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

Module 13 — Locking Internals: Row Locks, Table Locks, and Advisory Locks

What this module covers: Concurrency bugs in production are almost never about wrong SQL — they are about wrong locking assumptions. This module covers the complete PostgreSQL locking matrix from first principles: what every lock mode protects, how row-level locks differ from table-level locks, the precise semantics of FOR UPDATE vs FOR SHARE vs FOR NO KEY UPDATE, how ALTER TABLE can silently queue behind a single open transaction and take down your application, and how advisory locks let you build distributed coordination primitives directly inside Postgres.


Why Locking Is Hard to Reason About

Postgres has multiple, overlapping lock systems that operate at different granularities simultaneously:

  1. Table-level locks — protect the table structure and relation-level operations
  2. Row-level locks — protect individual tuple modifications
  3. Page-level locks — internal, mostly transparent (buffer pins)
  4. Advisory locks — application-defined locks with no automatic semantics

Every DML statement acquires locks at multiple levels simultaneously. An UPDATE acquires a RowExclusiveLock on the table and a row-level exclusive lock on each modified tuple. The two systems interact: some table-level operations must wait for all row-level locks to be released before they can proceed.

Understanding which operations conflict — and which do not — is the difference between a schema migration that completes in 30 seconds and one that causes a 20-minute outage.


Table-Level Lock Modes

Postgres defines 8 table-level lock modes, ordered from weakest to strongest. Each mode conflicts with some modes and is compatible with others.

The Full Lock Matrix

Lock ModeAcquired ByConflicts With
ACCESS SHARESELECTACCESS EXCLUSIVE only
ROW SHARESELECT FOR UPDATE/SHAREEXCLUSIVE, ACCESS EXCLUSIVE
ROW EXCLUSIVEINSERT, UPDATE, DELETESHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, ACCESS EXCLUSIVE
SHARE UPDATE EXCLUSIVEVACUUM, ANALYZE, CREATE INDEX CONCURRENTLY, ALTER TABLE ... VALIDATESHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, ACCESS EXCLUSIVE
SHARECREATE INDEX (non-concurrent)ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE ROW EXCLUSIVE, EXCLUSIVE, ACCESS EXCLUSIVE
SHARE ROW EXCLUSIVECREATE TRIGGER, some ALTER TABLEROW EXCLUSIVE and above
EXCLUSIVERare — some replication operationsEverything except ACCESS SHARE
ACCESS EXCLUSIVEALTER TABLE, DROP TABLE, TRUNCATE, VACUUM FULL, LOCK TABLEEverything including SELECT

The critical insight: ACCESS EXCLUSIVE conflicts with every other lock mode, including plain SELECT. This is why ALTER TABLE on a busy table causes an outage.

The ALTER TABLE Outage Pattern

This is one of the most common causes of production incidents. Here is the exact mechanism:

sql

The ALTER TABLE does not hold a lock — it is waiting for one. But its waiting position in the lock queue blocks all subsequent requests, even ones that would normally be compatible with each other.

sql

The Correct ALTER TABLE Pattern

sql

The window between killing queries and running the ALTER must be short — new long-running queries can start in the gap.

Lock Modes in Practice

sql

Row-Level Locks

Table-level locks protect the schema. Row-level locks protect individual tuples from concurrent modification. They are separate systems.

The Four Row Lock Modes

FOR UPDATE

  • Strongest row lock. Marks the row as being updated.
  • Blocks: other FOR UPDATE, FOR NO KEY UPDATE, FOR SHARE, FOR KEY SHARE
  • Use when: you intend to update or delete the row, or you need to prevent any concurrent modification

FOR NO KEY UPDATE

  • Like FOR UPDATE but does not block FOR KEY SHARE
  • Use when: updating non-key columns (foreign keys to this row remain unblocked)
  • Postgres uses this internally for UPDATE statements that don't modify key columns

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.