Skip to content

C14 — WAL Growth & Generation Rate

WAL as a raw, growing resource, independent of whether archiving or replication is keeping up with it: how much WAL currently sits on disk, how fast new WAL is being generated, and the full-page-write ratio that drives a lot of that volume right after each checkpoint. Read together with categories 02 and 09 for the complete picture — this category answers "how much WAL, how fast," not "is it being cleared out fast enough," which is what those two cover instead.

13 checks, PGHF14-001 through PGHF14-013. Every check here is PGHF-namespace and built-in — see Metadata Columns Explained for what each field below actually means, and Resetting to Defaults for why these definitions can't be hand-edited in place.

PGHF14-001 — pg_wal directory size

Uncontrolled WAL accumulation can exhaust the filesystem and crash the server — this is the single top-level number that summarizes whatever combination of archiving, replication-slot, or checkpoint problems (PGHF02/PGHF09/PGHF14 elsewhere) is driving WAL growth.

How to fix

This is a summary signal — the actual fix is in whichever specific check is the root cause:

  1. PGHF02-001/PGHF02-002 — archiving stalled or failing.
  2. PGHF09-001/PGHF09-011 — an inactive replication slot retaining WAL.
  3. PGHF14-012 — a long-running transaction blocking WAL recycling.
  4. PGHF03-008/PGHF14-011max_wal_size too small, forcing frequent checkpoints (this doesn't directly grow pg_wal, but a too-small ceiling combined with any of the above compounds faster).

Check those before assuming this needs a filesystem-level fix (adding disk space just delays the same underlying problem).

PGHF14-002 — WAL generation rate

An abnormally high real-time WAL production rate points at bulk writes, a full-page-write storm right after a checkpoint, or a configuration change — this is the leading indicator, with PGHF14-001's directory size as the lagging consequence.

How to fix

  1. If the spike aligns with checkpoints, check PGHF14-004's full-page-write ratio — a high rate right after each checkpoint is expected behavior, not a defect, and wal_compression (PGHF03-009) shrinks it.
  2. If it's sustained rather than periodic, find the source with PGHF14-005's top-WAL-generating-tables breakdown.
  3. If it's a genuine, unexpected step-change, check recent deploys/migrations for a new bulk-write pattern or a changed batch job.

PGHF14-003 — WAL statistics summary

A high wal_buffers_full count in this summary means WAL buffer space is undersized for the write rate, causing contention on the WAL write lock — a distinct root cause from PGHF03-013's static wal_buffers setting, observed here as it actually happens.

How to fix

See PGHF03-013's remediation — raise wal_buffers explicitly (requires a restart) rather than leaving it at auto-sized -1; this summary is exactly what confirms whether that change actually helped (re-check wal_buffers_full after the change, over a comparable load period).

PGHF14-004 — Full-page write ratio

A high full-page-image ratio means most WAL volume is full 8kB page copies rather than compact change records — usually a sign of undersized shared_buffers or an aggressive checkpoint schedule forcing repeated first-writes-after-checkpoint.

How to fix

  1. Enable wal_compression (PGHF03-009) — the most direct lever, shrinks full-page images without changing checkpoint behavior.
  2. Raise checkpoint_completion_target/max_wal_size (PGHF03-007/PGHF03-008) so checkpoints happen less often, reducing how frequently the first-write-after-checkpoint full-page-write cost is paid.
  3. If shared_buffers is undersized (PGHF03-001), pages get evicted and re-dirtied more often than necessary, indirectly increasing full-page writes too.

PGHF14-005 — Top WAL-generating tables

When PGHF14-001/PGHF14-002 flag elevated WAL, this is where to look next — the specific tables generating the most WAL are the concrete, actionable target for investigation, rather than a cluster-wide number with no obvious next step.

How to fix

For a table dominating WAL generation: check whether it's a genuine high-write workload (nothing to fix) or an inefficient write pattern — frequent small updates that could be batched, an index that's more expensive to maintain than it's worth (PGHF06-001/PGHF06-007), or a column being updated that could use HOT updates instead (avoid indexing columns that change on every write, when possible) to reduce per-update WAL volume.

PGHF14-006 — WAL compression

With wal_compression off, full-page images (see PGHF14-004) consume more WAL volume and replication bandwidth than necessary — enabling it directly shrinks the thing PGHF14-004 measures, usually for a modest and worthwhile CPU cost.

How to fix

See PGHF03-009's remediation — ALTER SYSTEM SET wal_compression = 'zstd' (or lz4), then SELECT pg_reload_conf();.

PGHF14-007 — wal_level vs logical replication usage

Logical WAL is materially larger than replica-level WAL for the same write workload — wal_level=logical with no actual logical slots or Spock subscriptions using it means paying that overhead for no benefit.

How to fix

If nothing actually uses logical decoding (no logical slots, no Spock nodes — check PGHF12-019), drop back to replica:

ALTER SYSTEM SET wal_level = 'replica';

Requires a restart. If logical decoding is planned but not yet set up, this is expected overhead, not a problem — leave wal_level = logical in place.

PGHF14-008 — WAL segment count

A high segment count indicates WAL recycling is blocked — typically by an inactive replication slot (PGHF09-011) or a long-running transaction (PGHF14-012) holding back the oldest segment PostgreSQL would otherwise reclaim.

How to fix

Check PGHF09-011 (inactive slots) and PGHF14-012 (long transactions) first — both are the common causes and this check's own segment count should drop once either is resolved. If neither applies, check PGHF02-002/PGHF14-009 for a stalled archiver, which also blocks recycling until archiving catches up.

PGHF14-009 — WAL archiver status

Unarchived WAL fills pg_wal and can crash the server — this reads the same pg_stat_archiver data as PGHF02-002 but focused specifically on how long it's actually been since the last successful archive, not just the failure count.

How to fix

See PGHF02-002's remediation — find the archiver's actual failure reason in the log and fix the underlying cause (permissions, network, destination disk space).

PGHF14-010 — UNLOGGED tables advisory

Converting an UNLOGGED table to LOGGED triggers a large one-time WAL spike as its full contents get written to WAL — worth knowing which tables are UNLOGGED before anyone runs that ALTER TABLE without planning for the burst.

How to fix

No fix needed by default — this is informational. If a specific table listed here needs to become LOGGED (e.g. it turned out to need crash-safety or replication after all), plan for the one-time WAL spike:

ALTER TABLE schema.the_table SET LOGGED;

Run it during a lower-traffic window if the table is large, since the conversion rewrites the table and generates WAL proportional to its full size.

PGHF14-011 — Forced checkpoint rate

Checkpoints forced by WAL volume rather than the schedule mean max_wal_size is too small for the current write rate — same underlying signal as PGHF03-008, but scoped specifically to WAL growth rather than general checkpoint tuning.

How to fix

See PGHF03-008's remediation — raise max_wal_size so checkpoints follow the checkpoint_timeout schedule instead of being forced by volume:

ALTER SYSTEM SET max_wal_size = '4GB';
SELECT pg_reload_conf();

PGHF14-012 — Long transactions blocking WAL recycle

An old open transaction holds a snapshot that prevents PostgreSQL from discarding older WAL segments — one of the most common and easily-overlooked causes of PGHF14-008's segment-count growth, and fixable simply by ending the offending transaction.

How to fix

See PGHF01-004/PGHF04-001's remediation — find the long-running session in pg_stat_activity and end it (pg_cancel_backend()/pg_terminate_backend()), then set statement_timeout/idle_in_transaction_session_timeout as a backstop against recurrence.

PGHF14-013 — WAL accumulation since checkpoint

WAL generated since the last checkpoint is "reserved" and can't be recycled until the next one completes — nearing max_wal_size here is what actually triggers a forced checkpoint (PGHF14-011), making this the earlier warning signal.

How to fix

See PGHF14-011's remediation — raise max_wal_size proactively if this is trending toward the ceiling regularly, rather than waiting for PGHF14-011 to confirm checkpoints are already being forced.

Continue to C15 — Replication Health.