keep-daily Buckets by Local DayA 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.
PBS prune options are not independent counts of snapshots. Each one defines time buckets and keeps the newest snapshot in each bucket:
keep-last N — the N most recent snapshots, regardless of when they happened. The only
option that counts snapshots rather than periods.keep-hourly N — newest snapshot from each of the last N clock hours.keep-daily N — newest from each of the last N calendar days.keep-weekly / keep-monthly / keep-yearly — the same idea at
larger granularity.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.
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.
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.
keep-daily with a keep-last floorkeep-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.
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.
--comment field is capped at 128 characters, which is easy to trip
over when scripting job creation with a descriptive note.keep-last. It costs a little disk and
removes an entire class of surprise.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.