Cookbook recipe

Table-Level Lock Blocking DDL (ALTER TABLE)

Applies to PostgreSQL 13–17 Last reviewed May 2026 Grounded in source
Estimated investigation4 min

Scenario

Scenario A DBA runs ALTER TABLE orders ADD COLUMN delivery_eta TIMESTAMPTZ during business hours. The command hangs for 30 minutes. Meanwhile, the application's connection pool fills to capacity because every query against the orders table —…

Investigation Path

Scenario

A DBA runs ALTER TABLE orders ADD COLUMN delivery_eta TIMESTAMPTZ during business hours. The command hangs for 30 minutes. Meanwhile, the application’s connection pool fills to capacity because every query against the orders table — SELECTs, INSERTs, UPDATEs — is queued behind the DDL waiting for an ACCESS EXCLUSIVE lock. The table itself is locked because an open read transaction, started before the ALTER, is still active.

How to Identify

Conditions:

  • ALTER TABLE or other DDL command appears in pg_stat_activity with state = 'active' but no progress for minutes
  • pg_locks shows the DDL session waiting for AccessExclusiveLock with granted = false
  • A large number of subsequent sessions are stacked behind the DDL, also blocked
  • Application connection count spikes; pool exhaustion errors appear in application logs
  • The root blocker may be an innocuous long-running SELECT or an idle in transaction session

Analysis Steps

-- 1. Find all sessions blocked on lock waits (includes DDL and its followers)
SELECT
    pid,
    usename,
    state,
    wait_event_type,
    wait_event,
    now() - query_start   AS wait_duration,
    left(query, 100)      AS query
FROM   pg_stat_activity
WHERE  wait_event_type = 'Lock'
ORDER  BY wait_duration DESC;

-- 2. Identify blocker → blocked chains
SELECT
    blocking.pid                       AS blocking_pid,
    blocking.state                     AS blocking_state,
    now() - blocking.xact_start        AS blocking_xact_age,
    left(blocking.query, 80)           AS blocking_query,
    blocked.pid                        AS blocked_pid,
    left(blocked.query, 80)            AS blocked_query
FROM   pg_stat_activity blocked
JOIN   pg_stat_activity blocking
    ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
WHERE  cardinality(pg_blocking_pids(blocked.pid)) > 0;

-- 3. Check AccessExclusiveLock waits specifically (DDL indicator)
SELECT
    l.pid,
    l.relation::regclass    AS table_name,
    l.mode,
    l.granted,
    a.state,
    left(a.query, 80)       AS query
FROM   pg_locks l
JOIN   pg_stat_activity a ON a.pid = l.pid
WHERE  l.mode = 'AccessExclusiveLock'
ORDER  BY l.granted DESC;

-- 4. Count how many sessions are blocked (connection pile-up indicator)
SELECT count(*) AS queued_sessions
FROM   pg_stat_activity
WHERE  wait_event_type = 'Lock';

Pitfalls

  • DDL in production without a maintenance window or lock_timeout will cause an outage if any long transaction is active — even a read-only one.
  • Do not run ALTER TABLE without first checking for long-running transactions on the target table; a single open SELECT can block the entire table.
  • lock_timeout is critical for DDL scripts — without it, the DDL waits indefinitely and queues all subsequent queries behind it, amplifying the outage.
  • Once the DDL acquires its position in the lock queue, all subsequent queries to the same table also queue behind it, even if the DDL itself is instantaneous once it starts.
  • Avoid pg_cancel_backend() on the DDL itself unless intentional — cancelling it releases the queue position, but blocked sessions are already waiting and need to be re-dispatched by the application.

Resolution Approach

Immediately cancel or terminate the root blocker (the session holding the conflicting lock), then cancel the DDL itself if it is safe to do so. Going forward, always set lock_timeout before DDL so it fails fast instead of queuing. For large tables, prefer CREATE INDEX CONCURRENTLY or pg_repack for schema changes that need to avoid table locks entirely.

This is a Pro lesson

Get every Learning Pathway and cookbook recipe — grounded in PostgreSQL source code, with diagnostics, fixes, and prevention for each topic.

Continue this lesson to learn:

  • Mitigation Actions
  • All 36 Learning Pathway lessons
  • 170+ cookbook recipes
  • Source-grounded diagnostics & fixes

Secure checkout Cancel anytime Source-grounded

Career Impact

This scenario builds production judgment and operational confidence under pressure.

Open Career Dashboard →

Keep going

Related & next steps

Was this helpful?

← All cookbook recipes