Home / Alt manpages / pg_archivecleanup(1)

  • pg_archivecleanup(1)
  • User command
  • linux

Safely Retire Old PostgreSQL WAL Files with pg_archivecleanup

You will finish with a tested way to preview and remove PostgreSQL write-ahead log files older than a chosen WAL segment, including compressed archive files. The installed utility is PostgreSQL 16.15, packaged here as 16.15-0ubuntu0.24.04.1.

Allow about fifteen minutes for a dry run and a little longer if you are changing a standby configuration. You need a readable archive directory and a WAL filename that is safe to keep. The real cleanup is destructive: once old files are removed, recovery or another standby may no longer be able to read them from this directory.

1. Confirm the installed command

Check the binary and version first. These are ordinary, read-only commands and do not need elevated privileges:

$ command -v pg_archivecleanup
/usr/bin/pg_archivecleanup
$ pg_archivecleanup --version
pg_archivecleanup (PostgreSQL) 16.15 (Ubuntu 16.15-0ubuntu0.24.04.1)

The command takes two positional arguments: ARCHIVELOCATION, the directory containing archived WAL files, and OLDESTKEPTWALFILE, the oldest WAL file that must remain. Files logically before that point are candidates for removal.

Checkpoint: stop here if this is not the PostgreSQL installation used by the standby or archive process you are investigating. Different PostgreSQL installations can place different versions of the utility on PATH.

2. Identify the archive and keep point

Use the actual archive directory, not a PostgreSQL data directory chosen by guesswork. The directory must be readable and writable by the server-owning user. Inspect it without changing anything:

$ ls -la /path/to/wal-archive
$ test -d /path/to/wal-archive && echo 'archive directory exists'
$ test -r /path/to/wal-archive && test -w /path/to/wal-archive && echo 'archive is readable and writable'

Replace /path/to/wal-archive with a real path and replace 000000010000003700000010 below with the WAL segment that must be retained. Do not use the newest-looking filename merely because it is convenient. The keep point should come from the standby recovery state or the backup and retention procedure that owns this archive.

3. Preview the files that would be removed

Run a dry run with -n. It prints candidate filenames to standard output and leaves the directory unchanged:

$ pg_archivecleanup -n /path/to/wal-archive 000000010000003700000010
/path/to/wal-archive/00000001000000370000000E
/path/to/wal-archive/00000001000000370000000F

Your list will differ. The useful checks are that every listed file is in the intended directory, each filename is older than the keep point, and no unrelated marker, metadata or backup file appears. A dry run returning no filenames means there is nothing matching the cleanup rule; it does not mean that a different archive path is safe.

For more detail, add -d. Debug messages go to standard error, while the dry-run names remain on standard output:

$ pg_archivecleanup -n -d /path/to/wal-archive 000000010000003700000010
pg_archivecleanup: keeping WAL file "/path/to/wal-archive/000000010000003700000010" and later
pg_archivecleanup: file "/path/to/wal-archive/00000001000000370000000E" would be removed

The exact list and quoting vary with the directory contents. Do not skip this checkpoint before using a command that can delete files.

4. Handle backup names and compressed files

If the keep argument ends in .backup or .partial, pg_archivecleanup uses the filename prefix as the WAL keep point. This lets you anchor cleanup to a base backup without treating the suffix as part of the WAL segment:

$ pg_archivecleanup -n /path/to/wal-archive \
    000000010000003700000010.00000020.backup

For compressed archives, tell the utility which suffix to strip before it compares names. The extension includes its leading dot:

$ pg_archivecleanup -n -x .gz /path/to/wal-archive \
    000000010000003700000010
/path/to/wal-archive/00000001000000370000000E.gz

Only use -x when the files really have that extension. Without it, compressed names do not compare as the corresponding WAL filenames. Preview the compressed case separately and check that the output names are the files you expect.

5. Perform the cleanup only after review

There is no separate delete switch. Removing -n performs the operation, so review the dry-run output first and make sure no other standby or long-term archive depends on this directory:

$ pg_archivecleanup /path/to/wal-archive 000000010000003700000010
$ printf 'exit status: %s\n' "$?"
exit status: 0

This changes state by deleting eligible archive files. Run it as the server-owning user where possible. Use elevated privileges only when the archive permissions genuinely require them, and confirm the path again before adding sudo. An incorrect path or keep point can remove recovery material. There is no undo command; recovery requires restoring the deleted files from another copy or backup.

For a compressed archive, repeat the reviewed -x option in the real command:

$ pg_archivecleanup -x .gz /path/to/wal-archive \
    000000010000003700000010

6. Configure a standby cleanup command

For a standby, PostgreSQL can pass its recovery keep point to the utility through the %r substitution. In the standby's postgresql.conf, the documented shape is:

archive_cleanup_command = 'pg_archivecleanup /path/to/standby/archive %r'

Here the archive should be a transient staging area for that particular standby. Do not use this setting for a long-term WAL archive or a directory shared by multiple standbys recovering from the same files. Those consumers can need WAL that this standby has already moved past.

After changing the configuration, apply it through your normal PostgreSQL change and reload process, then inspect the server logs and archive directory. Keep the previous configuration line until the standby has been observed through a recovery checkpoint. If the cleanup is too aggressive, remove or restore the setting and recover the required WAL from the long-term archive.

Common mistakes

  • Using a long-term archive as a standby staging directory. The utility cannot know about other consumers.
  • Skipping -n and discovering the path or keep point was wrong after deletion.
  • Forgetting -x .gz for compressed files, so the comparison does not match the stored names.
  • Assuming a successful exit status proves that the retention policy was correct. It only reports that the command completed.
  • Running as root before checking ownership. Fix the archive permissions or use the correct service account where possible.

Done means

  • The PostgreSQL 16.15 executable and archive directory were confirmed.
  • A dry run showed only WAL files that were safe to retire.
  • Backup, partial and compressed filename handling was matched to the archive.
  • Any real deletion was reviewed as an irreversible change.
  • Standby cleanup is used only for a private transient staging area, not a shared or long-term archive.