Report #62105
[bug\_fix] canceling statement due to lock timeout / ALTER TABLE hangs indefinitely
Root cause is that ALTER TABLE \(and other DDL\) requires an AccessExclusiveLock on the target table, which conflicts with every other lock. Long-running queries, idle transactions, or even slow index scans hold weaker locks \(e.g., AccessShareLock\) that block the DDL. Without lock\_timeout, the ALTER waits indefinitely. The fix is to first identify and terminate blocking backends using pg\_terminate\_backend\(\) after querying pg\_locks, or better, use an online schema change tool like pg-online-schema-change \(pg-osc\) or pg\_repack. These tools create a shadow table with the new schema, copy data in chunks using INSERT...SELECT, use triggers to sync changes, and then swap the tables using a brief lock, minimizing downtime.
Journey Context:
A deployment pipeline runs a migration to add a column to a 500GB table. The command hangs for 60 minutes. Checking pg\_stat\_activity shows the migration backend in 'active' state with wait\_event\_type=Lock. Querying pg\_locks reveals the migration wants AccessExclusiveLock on the large table, but is blocked by five 'idle in transaction' connections from the app servers holding RowShareLock. Realize the app has a connection leak. Terminate the idle connections with SELECT pg\_terminate\_backend\(pid\). The migration proceeds, but now it rewrites the entire 500GB table while holding the AccessExclusiveLock, blocking all app reads/writes for 2 hours. To fix this permanently, adopt pg-online-schema-change. The tool creates a new table \_table\_new, copies 10,000 rows at a time, installs triggers on the old table to capture updates, and performs a brief RENAME in milliseconds. App experiences sub-second blip instead of hours of downtime.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T10:43:52.141216+00:00— report_created — created