Skip to content

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

Return to the regular view of this page.

Client waits

PostgreSQL waiting for an application, network socket, TLS/GSS handshake, or replication client.

Client flips the usual suspicion: PostgreSQL is ready to read, write, or complete a protocol step, and the remote side or network has not progressed. A large client-wait population is often normal for pooled idle connections.

State and transaction age decide severity

ClientRead plus state = 'idle' is expected. The same event with idle in transaction and an old xact_start can retain locks, snapshots, and dead tuples. ClientWrite on active sessions suggests the server cannot hand results to the consumer fast enough.

  • Normal: idle pooled sessions waiting for the next command.
  • Watch: old idle in transaction, active ClientWrite, handshake waits, or application latency at the same time.
  • Urgent: clients stop consuming results, connection slots are exhausted, open transactions block cleanup, or a replication client disconnects repeatedly.

Events to recognize

Event First owner to contact
ClientRead Application/connection pool
ClientWrite Application consumer or network
GssOpenServer Authentication/network path
SslOpenServer TLS handshake path
LibpqwalreceiverReceive Upstream primary/network
WalSenderWriteData Standby or replication client

Common misreads

  • “Most sessions are in ClientRead” is not a database bottleneck without state, transaction age, and pool sizing.
  • Cancelling an idle client does not fix an oversized pool; it only makes the pool reconnect.
  • ClientWrite can be caused by a slow consumer even when the database host network looks idle.
  • Replication-flavoured Client waits belong to the same protocol boundary but have different operational owners.

1 - Client: ClientRead

Waiting to read data from the client
PostgreSQL wait event dossier
ClassClient EventClientRead VersionsPG 13-18 Evidence2 source location(s)

Official description

Waiting to read data from the client

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

Trigger mechanism

WAIT_EVENT_CLIENT_READ at src/backend/libpq/be-secure.c:219 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:85. The instrumented operation is: Waiting to read data from the client. The frontend protocol path reports ClientRead immediately before a socket, TLS/GSS, or replication-client operation blocks. PostgreSQL is waiting for the remote side or network to progress.

Normal or trouble?

  • Normal: Idle ClientRead sessions are normal connection-pool inventory.
  • Investigate: Investigate active writes, handshakes, old idle-in-transaction sessions, connection exhaustion, or replication-client stalls.

Diagnostic SQL

Sessions waiting on Client/ClientRead
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 = 'Client'
  AND wait_event = 'ClientRead'
ORDER BY query_age DESC NULLS LAST;
Current Client 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 = 'Client'
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 = 'Client'
  AND a.wait_event = 'ClientRead'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Check state and transaction age before counting the wait as load.
  2. Correlate with the owning application, pool, and network path.
  3. Fix consumer backpressure or pool policy rather than repeatedly terminating connections.

Source evidence

2 - Client: ClientWrite

Waiting to write data to the client
PostgreSQL wait event dossier
ClassClient EventClientWrite VersionsPG 13-18 Evidence2 source location(s)

Official description

Waiting to write data to the client

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

Trigger mechanism

WAIT_EVENT_CLIENT_WRITE at src/backend/libpq/be-secure.c:344 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:86. The instrumented operation is: Waiting to write data to the client. The frontend protocol path reports ClientWrite immediately before a socket, TLS/GSS, or replication-client operation blocks. PostgreSQL is waiting for the remote side or network to progress.

Normal or trouble?

  • Normal: Idle ClientRead sessions are normal connection-pool inventory.
  • Investigate: Investigate active writes, handshakes, old idle-in-transaction sessions, connection exhaustion, or replication-client stalls.

Diagnostic SQL

Sessions waiting on Client/ClientWrite
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 = 'Client'
  AND wait_event = 'ClientWrite'
ORDER BY query_age DESC NULLS LAST;
Current Client 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 = 'Client'
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 = 'Client'
  AND a.wait_event = 'ClientWrite'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Check state and transaction age before counting the wait as load.
  2. Correlate with the owning application, pool, and network path.
  3. Fix consumer backpressure or pool policy rather than repeatedly terminating connections.

Source evidence

3 - Client: GssOpenServer

Waiting to read data from the client while establishing a GSSAPI session
PostgreSQL wait event dossier
ClassClient EventGssOpenServer VersionsPG 17-18 Evidence4 source location(s)

Official description

Waiting to read data from the client while establishing a GSSAPI session

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

Earlier names: Client/GSSOpenServer (PG 13-16)

Trigger mechanism

WAIT_EVENT_GSS_OPEN_SERVER at src/backend/libpq/be-secure-gssapi.c:461 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event.c:277. The instrumented operation is: Waiting to read data from the client while establishing a GSSAPI session. The frontend protocol path reports GssOpenServer immediately before a socket, TLS/GSS, or replication-client operation blocks. PostgreSQL is waiting for the remote side or network to progress.

Normal or trouble?

  • Normal: Idle ClientRead sessions are normal connection-pool inventory.
  • Investigate: Investigate active writes, handshakes, old idle-in-transaction sessions, connection exhaustion, or replication-client stalls.

Diagnostic SQL

Sessions waiting on Client/GssOpenServer
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 = 'Client'
  AND wait_event = 'GssOpenServer'
ORDER BY query_age DESC NULLS LAST;
Current Client 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 = 'Client'
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 = 'Client'
  AND a.wait_event = 'GssOpenServer'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Check state and transaction age before counting the wait as load.
  2. Correlate with the owning application, pool, and network path.
  3. Fix consumer backpressure or pool policy rather than repeatedly terminating connections.

Source evidence

4 - Client: LibpqwalreceiverConnect

Waiting in WAL receiver to establish connection to remote server
PostgreSQL wait event dossier
ClassClient EventLibpqwalreceiverConnect VersionsPG 17-18 Evidence4 source location(s)

Official description

Waiting in WAL receiver to establish connection to remote server

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

Earlier names: Client/LibPQWalReceiverConnect (PG 13-16)

Trigger mechanism

WAIT_EVENT_LIBPQWALRECEIVER_CONNECT at src/backend/replication/libpqwalreceiver/libpqwalreceiver.c:231 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event.c:280. The instrumented operation is: Waiting in WAL receiver to establish connection to remote server. The frontend protocol path reports LibpqwalreceiverConnect immediately before a socket, TLS/GSS, or replication-client operation blocks. PostgreSQL is waiting for the remote side or network to progress.

Normal or trouble?

  • Normal: Idle ClientRead sessions are normal connection-pool inventory.
  • Investigate: Investigate active writes, handshakes, old idle-in-transaction sessions, connection exhaustion, or replication-client stalls.

Diagnostic SQL

Sessions waiting on Client/LibpqwalreceiverConnect
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 = 'Client'
  AND wait_event = 'LibpqwalreceiverConnect'
ORDER BY query_age DESC NULLS LAST;
Current Client 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 = 'Client'
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 = 'Client'
  AND a.wait_event = 'LibpqwalreceiverConnect'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Check state and transaction age before counting the wait as load.
  2. Correlate with the owning application, pool, and network path.
  3. Fix consumer backpressure or pool policy rather than repeatedly terminating connections.

Source evidence

5 - Client: LibpqwalreceiverReceive

Waiting in WAL receiver to receive data from remote server
PostgreSQL wait event dossier
ClassClient EventLibpqwalreceiverReceive VersionsPG 17-18 Evidence4 source location(s)

Official description

Waiting in WAL receiver to receive data from remote server

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

Earlier names: Client/LibPQWalReceiverReceive (PG 13-16)

Trigger mechanism

WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE at src/backend/replication/libpqwalreceiver/libpqwalreceiver.c:876 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event.c:283. The instrumented operation is: Waiting in WAL receiver to receive data from remote server. The frontend protocol path reports LibpqwalreceiverReceive immediately before a socket, TLS/GSS, or replication-client operation blocks. PostgreSQL is waiting for the remote side or network to progress.

Normal or trouble?

  • Normal: Idle ClientRead sessions are normal connection-pool inventory.
  • Investigate: Investigate active writes, handshakes, old idle-in-transaction sessions, connection exhaustion, or replication-client stalls.

Diagnostic SQL

Sessions waiting on Client/LibpqwalreceiverReceive
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 = 'Client'
  AND wait_event = 'LibpqwalreceiverReceive'
ORDER BY query_age DESC NULLS LAST;
Current Client 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 = 'Client'
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 = 'Client'
  AND a.wait_event = 'LibpqwalreceiverReceive'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Check state and transaction age before counting the wait as load.
  2. Correlate with the owning application, pool, and network path.
  3. Fix consumer backpressure or pool policy rather than repeatedly terminating connections.

Source evidence

6 - Client: SslOpenServer

Waiting for SSL while attempting connection
PostgreSQL wait event dossier
ClassClient EventSslOpenServer VersionsPG 17-18 Evidence4 source location(s)

Official description

Waiting for SSL while attempting connection

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

Earlier names: Client/SSLOpenServer (PG 13-16)

Trigger mechanism

WAIT_EVENT_SSL_OPEN_SERVER at src/backend/libpq/be-secure-openssl.c:508 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event.c:286. The instrumented operation is: Waiting for SSL while attempting connection. The frontend protocol path reports SslOpenServer immediately before a socket, TLS/GSS, or replication-client operation blocks. PostgreSQL is waiting for the remote side or network to progress.

Normal or trouble?

  • Normal: Idle ClientRead sessions are normal connection-pool inventory.
  • Investigate: Investigate active writes, handshakes, old idle-in-transaction sessions, connection exhaustion, or replication-client stalls.

Diagnostic SQL

Sessions waiting on Client/SslOpenServer
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 = 'Client'
  AND wait_event = 'SslOpenServer'
ORDER BY query_age DESC NULLS LAST;
Current Client 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 = 'Client'
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 = 'Client'
  AND a.wait_event = 'SslOpenServer'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Check state and transaction age before counting the wait as load.
  2. Correlate with the owning application, pool, and network path.
  3. Fix consumer backpressure or pool policy rather than repeatedly terminating connections.

Source evidence

7 - Client: WaitForStandbyConfirmation

Waiting for WAL to be received and flushed by the physical standby
PostgreSQL wait event dossier
ClassClient EventWaitForStandbyConfirmation VersionsPG 17-18 Evidence2 source location(s)

Official description

Waiting for WAL to be received and flushed by the physical standby

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

Trigger mechanism

WAIT_EVENT_WAIT_FOR_STANDBY_CONFIRMATION at src/backend/replication/slot.c:3083 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:91. The instrumented operation is: Waiting for WAL to be received and flushed by the physical standby. The frontend protocol path reports WaitForStandbyConfirmation immediately before a socket, TLS/GSS, or replication-client operation blocks. PostgreSQL is waiting for the remote side or network to progress.

Normal or trouble?

  • Normal: Idle ClientRead sessions are normal connection-pool inventory.
  • Investigate: Investigate active writes, handshakes, old idle-in-transaction sessions, connection exhaustion, or replication-client stalls.

Diagnostic SQL

Sessions waiting on Client/WaitForStandbyConfirmation
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 = 'Client'
  AND wait_event = 'WaitForStandbyConfirmation'
ORDER BY query_age DESC NULLS LAST;
Current Client 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 = 'Client'
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 = 'Client'
  AND a.wait_event = 'WaitForStandbyConfirmation'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Check state and transaction age before counting the wait as load.
  2. Correlate with the owning application, pool, and network path.
  3. Fix consumer backpressure or pool policy rather than repeatedly terminating connections.

Source evidence

8 - Client: WalSenderWaitForWal

Waiting for WAL to be flushed in WAL sender process
PostgreSQL wait event dossier
ClassClient EventWalSenderWaitForWal VersionsPG 17-18 Evidence4 source location(s)

Official description

Waiting for WAL to be flushed in WAL sender process

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

Earlier names: Client/WalSenderWaitForWAL (PG 13-16)

Trigger mechanism

WAIT_EVENT_WAL_SENDER_WAIT_WAL at src/backend/replication/walsender.c:1714 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event.c:289. The instrumented operation is: Waiting for WAL to be flushed in WAL sender process. The frontend protocol path reports WalSenderWaitForWal immediately before a socket, TLS/GSS, or replication-client operation blocks. PostgreSQL is waiting for the remote side or network to progress.

Normal or trouble?

  • Normal: Idle ClientRead sessions are normal connection-pool inventory.
  • Investigate: Investigate active writes, handshakes, old idle-in-transaction sessions, connection exhaustion, or replication-client stalls.

Diagnostic SQL

Sessions waiting on Client/WalSenderWaitForWal
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 = 'Client'
  AND wait_event = 'WalSenderWaitForWal'
ORDER BY query_age DESC NULLS LAST;
Current Client 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 = 'Client'
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 = 'Client'
  AND a.wait_event = 'WalSenderWaitForWal'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Check state and transaction age before counting the wait as load.
  2. Correlate with the owning application, pool, and network path.
  3. Fix consumer backpressure or pool policy rather than repeatedly terminating connections.

Source evidence

9 - Client: WalSenderWriteData

Waiting for any activity when processing replies from WAL receiver in WAL sender process
PostgreSQL wait event dossier
ClassClient EventWalSenderWriteData VersionsPG 13-18 Evidence2 source location(s)

Official description

Waiting for any activity when processing replies from WAL receiver in WAL sender process

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

Trigger mechanism

WAIT_EVENT_WAL_SENDER_WRITE_DATA at src/backend/replication/walsender.c:1653 is the grep-verified reporting path. The public identity/resource is mapped at src/backend/utils/activity/wait_event_names.txt:93. The instrumented operation is: Waiting for any activity when processing replies from WAL receiver in WAL sender process. The frontend protocol path reports WalSenderWriteData immediately before a socket, TLS/GSS, or replication-client operation blocks. PostgreSQL is waiting for the remote side or network to progress.

Normal or trouble?

  • Normal: Idle ClientRead sessions are normal connection-pool inventory.
  • Investigate: Investigate active writes, handshakes, old idle-in-transaction sessions, connection exhaustion, or replication-client stalls.

Diagnostic SQL

Sessions waiting on Client/WalSenderWriteData
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 = 'Client'
  AND wait_event = 'WalSenderWriteData'
ORDER BY query_age DESC NULLS LAST;
Current Client 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 = 'Client'
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 = 'Client'
  AND a.wait_event = 'WalSenderWriteData'
ORDER BY a.pid, l.granted, l.locktype, l.mode;

Response

  1. Check state and transaction age before counting the wait as load.
  2. Correlate with the owning application, pool, and network path.
  3. Fix consumer backpressure or pool policy rather than repeatedly terminating connections.

Source evidence