← Back to Wiki
Backups

Proxmox Backup Server Retention: keep-daily Buckets by Local Day

A Proxmox Backup Server prune policy of keep-daily 7 reads like "keep a week of backups". It doesn't mean that. It means "keep the newest snapshot from each of the last 7 calendar days, in the server's local timezone" — and if your backups run near local midnight, two of them can land in the same bucket. A host with exactly two backups was one prune away from having one.

Share on X

How the buckets actually work

PBS prune options are not independent counts of snapshots. Each one defines time buckets and keeps the newest snapshot in each bucket:

A snapshot survives if any option wants it. The consequence people miss: because these are calendar buckets rather than rolling windows, two snapshots close together in time can compete for the same slot, and one of them loses.

The case that nearly cost a backup

A host had exactly two snapshots — a new machine, only just brought into the backup rotation:

2026-08-09T05:49Z
2026-08-10T04:53Z

Nearly 23 hours apart. Two different dates in UTC. Obviously two days of backups.

The backup server's local timezone was UTC−5. In local time:

2026-08-09T05:49Z  ->  2026-08-09 00:49 local
2026-08-10T04:53Z  ->  2026-08-09 23:53 local     <- same local day

Both fell on 2026-08-09 locally. With keep-daily 7 and no keep-last, PBS saw one day with two snapshots, kept the newest, and marked the other for deletion — taking a host with two backups down to one, while the policy still looked like a week of retention.

as stored (UTC) 08-09T05:49Z ✓ kept 08-10T04:53Z ✓ kept "two days of backups" UTC−5 as bucketed (local day) 08-09 00:49 ✗ pruned 08-09 23:53 ✓ newest wins one local day → one survivor keep-last 3 would have retained both — it counts snapshots, not calendar days.
Same two snapshots, two different verdicts. Nothing about the schedule was wrong — the bucket boundary simply fell between them in UTC and not in local time.

This isn't an edge case if your backups run in the early hours UTC. A fleet backing up between roughly 04:30 and 05:50 UTC is running right around local midnight in the Americas, so any of those jobs can straddle a local-day boundary and collide on the next run.

The fix: always pair keep-daily with a keep-last floor

keep-last counts snapshots, so it's immune to timezone bucketing. And because a snapshot survives if any rule wants it, keep-last can only ever retain more, never delete more — there is no downside beyond a little extra disk.

keep-last=3, keep-daily=7, keep-weekly=4, keep-monthly=6, keep-yearly=1

Adding keep-last 3 across every job fixed the latent version of this on jobs that had been running for months without anyone noticing. After the change, a full prune across five namespaces removed 12 snapshots out of 530 — all genuine same-day duplicates, with every namespace still holding one snapshot per distinct day.

Dry-run before you enable a prune job. Always.

Prune deletes. Reasoning about bucket semantics is exactly the kind of thing that feels obvious and isn't — this whole article is an example. PBS will tell you precisely what it intends to do:

proxmox-backup-client prune <group> \
  --repository <user@realm!token>@<host>:<datastore> \
  --ns <namespace> \
  --keep-last 3 --keep-daily 7 \
  --dry-run

It prints each snapshot with keep or remove. Read it per group rather than scanning the total, because the total looks reasonable in precisely the case that ruins you — one group losing its only spare copy is invisible in an aggregate.

Two more things worth knowing

Prevention

The one-line version: keep-daily keeps the newest snapshot per local calendar day, not per 24 hours, so backups near local midnight can collide and prune each other — pair it with keep-last, which counts snapshots and can only ever keep more, and dry-run every prune before you let it loose.