Understanding PostgreSQL Lock Modes in Production
In high-throughput production PostgreSQL databases, running innocent-looking DDL migrations like ALTER TABLE or CREATE INDEX can acquire an ACCESS EXCLUSIVE lock. This blocks all incoming read and write queries, causing connection pool exhaustion, request timeouts, and cascading downtime across application microservices.
Zero-Downtime Migration Rules
- Always use
CREATE INDEX CONCURRENTLY: Regular index creation blocks table writes for the entire duration of the B-tree scan.CONCURRENTLYbuilds the index in two passes without blocking writes. - Add Foreign Keys with
NOT VALID: Adding a foreign key constraint normally validates all rows under an exclusive lock. Splitting intoADD CONSTRAINT ... NOT VALIDfollowed byVALIDATE CONSTRAINTprevents write locks. - Always set a low
lock_timeout: SettingSET lock_timeout = '2s';ensures that if your migration cannot immediately acquire a lock due to an active query, it fails quickly instead of queueing behind it and blocking all subsequent traffic.