Skip to content

This is the multi-page printable view of this section. .

Return to the regular view of this page.

Timeout waits

Deliberate sleeps, retry intervals, throttles, and rate-limiting delays.

Timeout usually means PostgreSQL intentionally delayed work until a timer expires. The important question is not “why is the kernel slow?” but “which policy or safety mechanism inserted this delay?”

Identify the policy owner

Vacuum cost delay, recovery delay, backup throttling, checkpoint spreading, retry intervals, and pg_sleep() are designed waits. They become a problem when the policy no longer matches the service objective or when another bottleneck makes the delay recur excessively.

  • Normal: the configured policy is active and useful work advances at the expected rate.
  • Watch: foreground latency includes a deliberate sleep, or maintenance falls behind while spending much of its time throttled.
  • Urgent: recovery/backup/checkpoint deadlines are missed, a spin delay persists, or an operator did not intend the policy.

Events to recognize

Event Policy
VacuumDelay Cost-based vacuum throttling
CheckpointWriteDelay Spreading checkpoint writes across the interval
RecoveryApplyDelay Intentional delayed standby replay
RecoveryRetrieveRetryInterval Retrying unavailable WAL sources
BaseBackupThrottle Backup transfer-rate limit
PgSleep SQL or internal sleep function
SpinDelay Backoff while acquiring a contended spinlock

Common misreads

  • Timeout does not mean a statement or lock timeout fired; it means the process is currently sleeping on a timer.
  • Reducing vacuum delay can recover maintenance throughput but also increase I/O and CPU pressure.
  • RecoveryApplyDelay can be intentional disaster-recovery policy.
  • Persistent SpinDelay deserves escalation: a spinlock should normally be held for an extremely short time.

1 - Timeout: BaseBackupThrottle

Waiting during base backup when throttling activity
PostgreSQL wait event dossier
ClassTimeout EventBaseBackupThrottle VersionsPG 13-18 Evidence2 source location(s)

Official description

Waiting during base backup when throttling activity

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

Trigger mechanism

WAIT_EVENT_BASE_BACKUP_THROTTLE at src/backend/backup/basebackup_throttle.c:178 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:175. The instrumented operation is: Waiting during base backup when throttling activity. The BaseBackupThrottle path deliberately waits on a timer, retry interval, throttle, or safety backoff. The latch timeout expires before work is reconsidered.

Normal or trouble?

  • Normal: The wait is normal when the configured policy is intentional and useful work advances at the expected rate.
  • Investigate: Investigate when the policy causes missed maintenance, recovery, backup, or latency objectives, or when a spin delay persists.

Diagnostic SQL

Sessions waiting on Timeout/BaseBackupThrottle
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
  AND wait_event = 'BaseBackupThrottle'
ORDER BY query_age DESC NULLS LAST;
Current Timeout cohort
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
Lock and relation context for these sessions
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Timeout'
  AND a.wait_event = 'BaseBackupThrottle'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Identify the GUC or function that owns the timer.
  2. Compare productive work with time spent delayed.
  3. Adjust the policy only after checking the CPU, I/O, and durability pressure it was designed to control.

Source evidence

2 - Timeout: CheckpointWriteDelay

Waiting between writes while performing a checkpoint
PostgreSQL wait event dossier
ClassTimeout EventCheckpointWriteDelay VersionsPG 14-18 Evidence2 source location(s)

Official description

Waiting between writes while performing a checkpoint

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

Trigger mechanism

WAIT_EVENT_CHECKPOINT_WRITE_DELAY at src/backend/postmaster/checkpointer.c:814 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:176. The instrumented operation is: Waiting between writes while performing a checkpoint. The CheckpointWriteDelay path deliberately waits on a timer, retry interval, throttle, or safety backoff. The latch timeout expires before work is reconsidered.

Normal or trouble?

  • Normal: The wait is normal when the configured policy is intentional and useful work advances at the expected rate.
  • Investigate: Investigate when the policy causes missed maintenance, recovery, backup, or latency objectives, or when a spin delay persists.

Diagnostic SQL

Sessions waiting on Timeout/CheckpointWriteDelay
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
  AND wait_event = 'CheckpointWriteDelay'
ORDER BY query_age DESC NULLS LAST;
Current Timeout cohort
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
Lock and relation context for these sessions
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Timeout'
  AND a.wait_event = 'CheckpointWriteDelay'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Identify the GUC or function that owns the timer.
  2. Compare productive work with time spent delayed.
  3. Adjust the policy only after checking the CPU, I/O, and durability pressure it was designed to control.

Source evidence

3 - Timeout: PgSleep

Waiting due to a call to pg_sleep or a sibling function
PostgreSQL wait event dossier
ClassTimeout EventPgSleep VersionsPG 13-18 Evidence2 source location(s)

Official description

Waiting due to a call to pg_sleep or a sibling function

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

Trigger mechanism

WAIT_EVENT_PG_SLEEP at src/backend/utils/adt/misc.c:409 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:177. The instrumented operation is: Waiting due to a call to pg_sleep or a sibling function. The PgSleep path deliberately waits on a timer, retry interval, throttle, or safety backoff. The latch timeout expires before work is reconsidered.

Normal or trouble?

  • Normal: The wait is normal when the configured policy is intentional and useful work advances at the expected rate.
  • Investigate: Investigate when the policy causes missed maintenance, recovery, backup, or latency objectives, or when a spin delay persists.

Diagnostic SQL

Sessions waiting on Timeout/PgSleep
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
  AND wait_event = 'PgSleep'
ORDER BY query_age DESC NULLS LAST;
Current Timeout cohort
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
Lock and relation context for these sessions
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Timeout'
  AND a.wait_event = 'PgSleep'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Identify the GUC or function that owns the timer.
  2. Compare productive work with time spent delayed.
  3. Adjust the policy only after checking the CPU, I/O, and durability pressure it was designed to control.

Source evidence

4 - Timeout: RecoveryApplyDelay

Waiting to apply WAL during recovery because of a delay setting
PostgreSQL wait event dossier
ClassTimeout EventRecoveryApplyDelay VersionsPG 13-18 Evidence2 source location(s)

Official description

Waiting to apply WAL during recovery because of a delay setting

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

Trigger mechanism

WAIT_EVENT_RECOVERY_APPLY_DELAY at src/backend/access/transam/xlogrecovery.c:3092 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:178. The instrumented operation is: Waiting to apply WAL during recovery because of a delay setting. The RecoveryApplyDelay path deliberately waits on a timer, retry interval, throttle, or safety backoff. The latch timeout expires before work is reconsidered.

Normal or trouble?

  • Normal: The wait is normal when the configured policy is intentional and useful work advances at the expected rate.
  • Investigate: Investigate when the policy causes missed maintenance, recovery, backup, or latency objectives, or when a spin delay persists.

Diagnostic SQL

Sessions waiting on Timeout/RecoveryApplyDelay
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
  AND wait_event = 'RecoveryApplyDelay'
ORDER BY query_age DESC NULLS LAST;
Current Timeout cohort
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
Lock and relation context for these sessions
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Timeout'
  AND a.wait_event = 'RecoveryApplyDelay'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Identify the GUC or function that owns the timer.
  2. Compare productive work with time spent delayed.
  3. Adjust the policy only after checking the CPU, I/O, and durability pressure it was designed to control.

Source evidence

5 - Timeout: RecoveryRetrieveRetryInterval

Waiting during recovery when WAL data is not available from any source (pg_wal, archive or stream)
PostgreSQL wait event dossier
ClassTimeout EventRecoveryRetrieveRetryInterval VersionsPG 13-18 Evidence2 source location(s)

Official description

Waiting during recovery when WAL data is not available from any source (pg_wal, archive or stream)

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

Trigger mechanism

WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL at src/backend/access/transam/xlogrecovery.c:3764 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:179. The instrumented operation is: Waiting during recovery when WAL data is not available from any source (pg_wal, archive or stream). The RecoveryRetrieveRetryInterval path deliberately waits on a timer, retry interval, throttle, or safety backoff. The latch timeout expires before work is reconsidered.

Normal or trouble?

  • Normal: The wait is normal when the configured policy is intentional and useful work advances at the expected rate.
  • Investigate: Investigate when the policy causes missed maintenance, recovery, backup, or latency objectives, or when a spin delay persists.

Diagnostic SQL

Sessions waiting on Timeout/RecoveryRetrieveRetryInterval
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
  AND wait_event = 'RecoveryRetrieveRetryInterval'
ORDER BY query_age DESC NULLS LAST;
Current Timeout cohort
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
Lock and relation context for these sessions
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Timeout'
  AND a.wait_event = 'RecoveryRetrieveRetryInterval'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Identify the GUC or function that owns the timer.
  2. Compare productive work with time spent delayed.
  3. Adjust the policy only after checking the CPU, I/O, and durability pressure it was designed to control.

Source evidence

6 - Timeout: RegisterSyncRequest

Waiting while sending synchronization requests to the checkpointer, because the request queue is full
PostgreSQL wait event dossier
ClassTimeout EventRegisterSyncRequest VersionsPG 13-18 Evidence2 source location(s)

Official description

Waiting while sending synchronization requests to the checkpointer, because the request queue is full

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

Trigger mechanism

WAIT_EVENT_REGISTER_SYNC_REQUEST at src/backend/storage/sync/sync.c:615 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:180. The instrumented operation is: Waiting while sending synchronization requests to the checkpointer, because the request queue is full. The RegisterSyncRequest path deliberately waits on a timer, retry interval, throttle, or safety backoff. The latch timeout expires before work is reconsidered.

Normal or trouble?

  • Normal: The wait is normal when the configured policy is intentional and useful work advances at the expected rate.
  • Investigate: Investigate when the policy causes missed maintenance, recovery, backup, or latency objectives, or when a spin delay persists.

Diagnostic SQL

Sessions waiting on Timeout/RegisterSyncRequest
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
  AND wait_event = 'RegisterSyncRequest'
ORDER BY query_age DESC NULLS LAST;
Current Timeout cohort
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
Lock and relation context for these sessions
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Timeout'
  AND a.wait_event = 'RegisterSyncRequest'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Identify the GUC or function that owns the timer.
  2. Compare productive work with time spent delayed.
  3. Adjust the policy only after checking the CPU, I/O, and durability pressure it was designed to control.

Source evidence

7 - Timeout: SpinDelay

Waiting while acquiring a contended spinlock
PostgreSQL wait event dossier
ClassTimeout EventSpinDelay VersionsPG 16-18 Evidence2 source location(s)

Official description

Waiting while acquiring a contended spinlock

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

Trigger mechanism

WAIT_EVENT_SPIN_DELAY at src/backend/storage/lmgr/s_lock.c:148 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:181. The instrumented operation is: Waiting while acquiring a contended spinlock. The SpinDelay path deliberately waits on a timer, retry interval, throttle, or safety backoff. The latch timeout expires before work is reconsidered.

Normal or trouble?

  • Normal: The wait is normal when the configured policy is intentional and useful work advances at the expected rate.
  • Investigate: Investigate when the policy causes missed maintenance, recovery, backup, or latency objectives, or when a spin delay persists.

Diagnostic SQL

Sessions waiting on Timeout/SpinDelay
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
  AND wait_event = 'SpinDelay'
ORDER BY query_age DESC NULLS LAST;
Current Timeout cohort
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
Lock and relation context for these sessions
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Timeout'
  AND a.wait_event = 'SpinDelay'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Identify the GUC or function that owns the timer.
  2. Compare productive work with time spent delayed.
  3. Adjust the policy only after checking the CPU, I/O, and durability pressure it was designed to control.

Source evidence

8 - Timeout: VacuumDelay

Waiting in a cost-based vacuum delay point
PostgreSQL wait event dossier
ClassTimeout EventVacuumDelay VersionsPG 13-18 Evidence2 source location(s)

Official description

Waiting in a cost-based vacuum delay point

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

Trigger mechanism

WAIT_EVENT_VACUUM_DELAY at src/backend/commands/vacuum.c:2495 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:182. The instrumented operation is: Waiting in a cost-based vacuum delay point. The VacuumDelay path deliberately waits on a timer, retry interval, throttle, or safety backoff. The latch timeout expires before work is reconsidered.

Normal or trouble?

  • Normal: The wait is normal when the configured policy is intentional and useful work advances at the expected rate.
  • Investigate: Investigate when the policy causes missed maintenance, recovery, backup, or latency objectives, or when a spin delay persists.

Diagnostic SQL

Sessions waiting on Timeout/VacuumDelay
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
  AND wait_event = 'VacuumDelay'
ORDER BY query_age DESC NULLS LAST;
Current Timeout cohort
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
Lock and relation context for these sessions
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Timeout'
  AND a.wait_event = 'VacuumDelay'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Identify the GUC or function that owns the timer.
  2. Compare productive work with time spent delayed.
  3. Adjust the policy only after checking the CPU, I/O, and durability pressure it was designed to control.

Source evidence

9 - Timeout: VacuumTruncate

Waiting to acquire an exclusive lock to truncate off any empty pages at the end of a table vacuumed
PostgreSQL wait event dossier
ClassTimeout EventVacuumTruncate VersionsPG 15-18 Evidence2 source location(s)

Official description

Waiting to acquire an exclusive lock to truncate off any empty pages at the end of a table vacuumed

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

Trigger mechanism

WAIT_EVENT_VACUUM_TRUNCATE at src/backend/access/heap/vacuumlazy.c:3280 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:183. The instrumented operation is: Waiting to acquire an exclusive lock to truncate off any empty pages at the end of a table vacuumed. The VacuumTruncate path deliberately waits on a timer, retry interval, throttle, or safety backoff. The latch timeout expires before work is reconsidered.

Normal or trouble?

  • Normal: The wait is normal when the configured policy is intentional and useful work advances at the expected rate.
  • Investigate: Investigate when the policy causes missed maintenance, recovery, backup, or latency objectives, or when a spin delay persists.

Diagnostic SQL

Sessions waiting on Timeout/VacuumTruncate
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
  AND wait_event = 'VacuumTruncate'
ORDER BY query_age DESC NULLS LAST;
Current Timeout cohort
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
Lock and relation context for these sessions
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Timeout'
  AND a.wait_event = 'VacuumTruncate'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Identify the GUC or function that owns the timer.
  2. Compare productive work with time spent delayed.
  3. Adjust the policy only after checking the CPU, I/O, and durability pressure it was designed to control.

Source evidence

10 - Timeout: WalSummarizerError

Waiting after a WAL summarizer error
PostgreSQL wait event dossier
ClassTimeout EventWalSummarizerError VersionsPG 17-18 Evidence2 source location(s)

Official description

Waiting after a WAL summarizer error

PG 13 PG 14 PG 15 PG 16 PG 17 PG 18

Trigger mechanism

WAIT_EVENT_WAL_SUMMARIZER_ERROR at src/backend/postmaster/walsummarizer.c:337 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:184. The instrumented operation is: Waiting after a WAL summarizer error. The WalSummarizerError path deliberately waits on a timer, retry interval, throttle, or safety backoff. The latch timeout expires before work is reconsidered.

Normal or trouble?

  • Normal: The wait is normal when the configured policy is intentional and useful work advances at the expected rate.
  • Investigate: Investigate when the policy causes missed maintenance, recovery, backup, or latency objectives, or when a spin delay persists.

Diagnostic SQL

Sessions waiting on Timeout/WalSummarizerError
SELECT pid, backend_type, usename, datname, application_name,
       state, now() - query_start AS query_age,
       now() - xact_start AS xact_age,
       wait_event_type, wait_event,
       pg_blocking_pids(pid) AS blocking_pids,
       left(query, 160) AS query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
  AND wait_event = 'WalSummarizerError'
ORDER BY query_age DESC NULLS LAST;
Current Timeout cohort
SELECT wait_event, count(*) AS waiting_sessions,
       count(*) FILTER (WHERE state = 'active') AS active_waiters,
       max(now() - query_start) AS oldest_query
FROM pg_stat_activity
WHERE wait_event_type = 'Timeout'
GROUP BY wait_event
ORDER BY waiting_sessions DESC, wait_event;
Lock and relation context for these sessions
SELECT a.pid, l.locktype, l.mode, l.granted, l.fastpath,
       d.datname, n.nspname, c.relname,
       l.page, l.tuple, l.virtualxid, l.transactionid,
       l.classid, l.objid, l.objsubid
FROM pg_stat_activity AS a
LEFT JOIN pg_locks AS l ON l.pid = a.pid
LEFT JOIN pg_database AS d ON d.oid = l.database
LEFT JOIN pg_class AS c
  ON c.oid = l.relation
 AND l.database = (
       SELECT oid FROM pg_database WHERE datname = current_database()
     )
LEFT JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE a.wait_event_type = 'Timeout'
  AND a.wait_event = 'WalSummarizerError'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Identify the GUC or function that owns the timer.
  2. Compare productive work with time spent delayed.
  3. Adjust the policy only after checking the CPU, I/O, and durability pressure it was designed to control.

Source evidence