BTRFS-BACKUP-NG-VERIFY(1)
π btrfs-backup-ng-verify(1) π
okay so bestie, welcome to the manual page for btrfs-backup-ng-verify β that's the verify command from the btrfs-backup-ng suite, living in the User Commands section of the manual (yes, section 1, the cool one). pull up a chair, this one is long and it's lowkey important π
β¨ NAME β¨
btrfs-backup-ng-verify β verify backup integrity π«Ά
Like, does your backup actually work? That's the whole job.
π¦ SYNOPSIS π¦
btrfs-backup-ng verify [OPTIONS] LOCATION
πΈ DESCRIPTION πΈ
So the tea is this: btrfs-backup-ng verify checks that the backups sitting at a given LOCATION are valid and restorable. Not just "the folder has a name that looks right" β actually restorable. it gives you multiple levels of verification, going from a quick metadata glance all the way up to a full-blown restore test.
Verification works with btrfs backup subvolumes (both local directories and remote SSH locations), and also with raw targets (raw:// and raw+ssh://), which store btrfs send streams as plain files.
For a raw target, verification recomputes each stream's sha256 and compares it to the checksum sealed in the stream's .meta sidecar. That's literally the same integrity check performed by btrfs-backup-ng raw verify and before every raw restore. iconic consistency, no cap. π
π ARGUMENTS π
LOCATIONβ the backup location you want verified. It can be a local path (like/mnt/backup/home), an SSH URL (likessh://user@host:/path/to/backup), or a raw target (likeraw:///mnt/usb/backupsorraw+ssh://user@host:/backups). Pick your fighter. π
π OPTIONS π
--level LEVELβ which verification level to run. Default ismetadatafor a btrfs target, andstream(the sealed-checksum check) for a raw target. The reasoning is kinda cute honestly: a raw backup's integrity is whether its stored bytes still match what was written, so a bare verify on a raw target actually reads the stream rather than reporting a hollow pass from just looking at a directory listing. π Valid levels:metadataβ a fast structural check that each backup is a real backup artifact, not merely a name-shaped entry. For a btrfs target: confirms each entry is a received read-only subvolume (an interrupted receive that left a plain directory FAILS rather than passing), and an entry whose received status can't be confirmed without privilege is reported unverifiable rather than failed. For a raw target: confirms an authoritative.metasidecar is present, and when a snapshot records an incremental parent, that the parent actually exists among the backups (a recorded-but-absent parent is an unrestorable chain break and FAILS). This one is fast and non-destructive; it does not read stream/file data (usestreamorfullfor that).streamβ for a btrfs target, verify that a btrfs send stream can be generated (usesbtrfs send --no-datato test stream generation without transferring file data, validating that snapshot metadata is intact). For a raw target, recompute the stored stream'ssha256and compare it to the checksum sealed in its.metasidecar, detecting at-rest corruption.fullβ for a btrfs target, a complete restore test to a temporary location: it actually restores the target snapshot with a full btrfs send (reading every data block, so btrfs's own checksums catch at-rest corruption) and verifies the restored subvolume is valid. The most thorough check, but the slowest β and for a remote backup it pulls the whole snapshot over the network. Requires--temp-diron a local btrfs filesystem for remote backups, and root or passwordlesssudo(it runsbtrfs receive). If the restore test can't run β no privilege, or the target doesn't fit in the temp filesystem β the snapshot is reported unverifiable, not failed. For a raw target,fullperforms the same sealed-checksum verification asstream.
--snapshot NAMEβ verify only the named snapshot. Mutually exclusive with--all. (pick ONE bestie, they're not friends.)--allβ verify EVERY snapshot at the backup location. Thestreamandfulllevels only check the latest snapshot by default (fast!);--allverifies the whole chain. Themetadatalevel and raw targets already check all snapshots, so--allis a no-op there. Mutually exclusive with--snapshot.--temp-dir PATHβ temporary directory forfullverification. Must be on a btrfs filesystem. Required for full verification of remote backups. Created if it does not exist; without it, the temporary directory is made inside the backup location, which must exist.--no-cleanupβ do not delete restored snapshots after full verification. super useful for inspection or debugging π--prefix PREFIXβ only verify snapshots matching the given prefix.--ssh-sudoβ usesudofor btrfs commands on the remote host.--ssh-key FILEβ SSH private key file for authentication.--ssh-auth-sock PATHβ explicit ssh-agent socket (overrides auto-discovery; useful undersudo).--ssh-host-key-policy POLICYβ host-key verification for this run:accept-new(default) orstrict.--fs-checks MODEβ filesystem verification mode. Valid values:autoβ (default) warn about issues but continue operation.strictβ error out on filesystem check failures.skipβ bypass all filesystem verification checks.
--no-fs-checksβ skip btrfs subvolume verification checks. It's an alias for--fs-checks=skip. Useful when verifying backup directories which are regular directories, not subvolumes.--jsonβ output results in JSON format for scripting and automation. for the girlies who pipe things π€-q,--quietβ suppress progress output.--skip-remote-lockβ proceed even if a lock cannot be recorded on the remote target. > Only safe when nothing else can prune this target during the run. (like, genuinely. be careful. π)--timestamp-format FMTβstrftimeformat for parsing snapshot timestamps in direct mode (defaults to the config's[global] timestamp_format, else the built-in).
π VERIFICATION LEVELS π
π Metadata (Fast)
Checks performed, per snapshot:
- Structural validity β that the entry is a REAL backup artifact: a received read-only btrfs subvolume (non-empty received UUID), or a raw stream with an authoritative
.metasidecar. A plain directory (e.g. an interrupted receive) FAILS; an entry whose backup identity cannot be confirmed without privilege is reported unverifiable, not failed β a good backup is never failed merely because the environment could not prove it. π«Ά - Authoritative incremental-parent continuity β for a raw snapshot that records its parent's name, that the parent actually exists among the backups (a recorded-but-absent parent is an unrestorable chain break and FAILS). btrfs snapshots carry no recorded parent name at this level, so their chain is validated by full verification.
This level is fast and non-destructive and can verify hundreds of snapshots in seconds β‘; it does not read stream/file data.
π Stream (Medium)
In addition to metadata checks:
- Generates btrfs send stream with
--no-dataflag - Validates stream header and metadata integrity
- Does not transfer actual file data
This level catches corruption in snapshot metadata that metadata-only checks might miss. sneaky little bugs, caught. π
π§ Full (Thorough)
Performs an actual restore of the target snapshot:
- Full btrfs send of the target into a temp subvolume (no incremental parent needed β the backup's received subvolumes are already fully materialized), reading every data block
- Verifies the restored path is a valid btrfs subvolume
- Reports unverifiable (not failed) if the environment cannot run the test (no root/sudo, or the target does not fit in the temp filesystem)
- Cleans up the restored subvolume afterward (unless
--no-cleanup); a user-supplied--temp-diris never removed, only the restored subvolumes within it
This is the definitive test that a backup can be restored. Requires root or passwordless sudo, and --temp-dir on a local btrfs filesystem for remote backups. it's giving main character energy, but it's also the slowest. π
πΈ Raw targets (sealed checksum)
For a raw:// or raw+ssh:// target, the stream and full levels recompute each stored stream's sha256 and compare it to the checksum sealed in the stream's .meta sidecar. Every stream is checked (not just the latest). Per-snapshot status is one of:
okβ the stream matches its sealed checksum (intact). πcorruptβ the stream on disk no longer matches (fails; exit1).errorβ the stream could not be read to hash it (fails; exit1).unverifiableβ nosha256checksum was recorded (a legacy backup); not a failure, but reported explicitly rather than as a silent pass.
For a raw+ssh:// target the sha256 is recomputed on the (untrusted) remote host, so an ok verdict evidences at-rest consistency, not authenticity β a compromised target could forge a match. π³
Verify a locally-mounted raw:// copy for tamper-evidence.
π VERDICT AND COUNTS π
Every run reports one of three verdicts (the verdict field in --json; the final line in human output):
passβ every snapshot that was checked verified successfully.unverifiableβ no failures, but one or more snapshots could not be confirmed (an environmental limit, e.g. no privilege or a legacy backup with no recorded checksum). This is NOT a failure; a good backup is never reported bad because it could not be checked. πfailβ at least one snapshot failed, or a run-level error occurred.
The summary counts verified (positively confirmed), failed, and unverifiable separately β an unverifiable snapshot is never counted as verified. It also states how many snapshots were checked of how many are available; when only a subset was checked (the latest, at stream/full level), it hints to pass --all to verify the whole chain. periodt. π
β EXIT STATUS β
0β verdict pass or unverifiable (no failure detected; an environmental inability to verify does not raise an alarm).1β verdict fail β one or more verifications failed.2β run-level error (bad arguments, no snapshots found, temp directory unusable, etc.).
and bestie, there's more β
π EXAMPLES π
Lowkey the best part, bestie β here's every vibe of verify you could possibly want β¨
- Quick metadata check of local backup:
btrfs-backup-ng verify /mnt/backup/home
- Verify remote backup over SSH:
btrfs-backup-ng verify ssh://backup@server:/backups/home --ssh-sudo
- Stream integrity check:
btrfs-backup-ng verify /mnt/backup/home --level stream
- Full restore test:
btrfs-backup-ng verify /mnt/backup/home --level full --temp-dir /mnt/test
- Full verification of remote backup:
btrfs-backup-ng verify ssh://server:/backups/home --level full --temp-dir /mnt/test
- Verify a raw target (checks the sealed sha256 of every stream):
btrfs-backup-ng verify raw:///mnt/usb/backups
- Verify a remote raw target over SSH:
btrfs-backup-ng verify raw+ssh://backup@server:/backups --ssh-sudo
- Verify specific snapshot:
btrfs-backup-ng verify /mnt/backup/home --snapshot home-20260104-120000
- Verify the ENTIRE chain (every snapshot), not just the latest:
btrfs-backup-ng verify /mnt/backup/home --level stream --all
- JSON output for automation:
btrfs-backup-ng verify /mnt/backup/home --json
π OUTPUT π
So when you run verify, it shows you a table of per-snapshot results, and every single one gets a status that's very clear about how it's doing: PASS (green π’), UNVERIFIABLE (yellow π‘), or FAIL (red π΄). And then after the table comes a summary with the verified / failed / unverifiable counts, the checked-of-available count, and the verdict. Chef's kiss, no notes π
When you throw --json in there, the output is a JSON object containing:
verdict: the authoritative top-level result βpass,unverifiable, orfail. Monitoring should gate on this rather than re-deriving from counts. Like fr fr, just read the verdict, don't do math, trust the vibe check β¨level: Verification level usedlocation: Backup locationduration_seconds: Total verification timesummary:verified,failed,unverifiable,checked, andavailablecounts (passedandtotalare retained as back-compat aliases:passed= not-failed,total=checked)results: Array of individual snapshot results, each with a status ofok/failed/unverifiableerrors: Array of run-level error messages
π¦ AUTOMATION π¦
Okay bestie, if you want automated backup verification in scripts or cron, you gate on the verdict field. Periodt. That's the whole strategy π
#!/bin/bash
report=$(btrfs-backup-ng verify /mnt/backup/home --all --json)
verdict=$(printf '%s' "$report" | jq -r .verdict)
if [ "$verdict" = "fail" ]; then
printf '%s' "$report" | mail -s "Backup verification FAILED" admin@example.com
elif [ "$verdict" = "unverifiable" ]; then
printf '%s' "$report" | mail -s "Backup could not be fully verified" admin@example.com
fi
π«Ά SEE ALSO π«Ά
And that's the whole page, bestie β this one's from the btrfs-backup-ng fam, dated July 2026, and it's the BTRFS-BACKUP-NG-VERIFY(1) manual, iconic as always π
β¨ Go verify something and feel like the main character π
π¦ where this page comes from
- fedora 43: btrfs-backup-ng 0.9.20-2.fc43 Β· MIT
- fedora 44: btrfs-backup-ng 0.9.20-1.fc44 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms