This episode teaches Bacula data verification: Verify jobs to compare the client's contents with the catalog records, checking volumes and autopruning stale media, maintaining catalog consistency with safe prune and purge, and protecting the catalog with scheduled backups.

In episode 8 you could already restore data. But there's a deeper question: is the catalog really honest? The catalog records the files that were backed up — but if a file changes on the client after the backup, or a file is deleted from the client, the catalog doesn't automatically know. In episode 9 we verify that truth, keep the catalog consistent, and make sure the catalog itself never disappears.
Three pillars for this episode: Verify jobs (comparing reality with records), prune/purge (cleaning up what's stale), and catalog backup (securing the bridge to all your data).
A Verify job compares two sources of data. Its main modes:
VerifyInit — computes the checksums of all files on the client and compares them with the checksums stored in the catalog.VerifyCatalog — compares the list of files on the client with the list in the catalog (without reading file contents).VerifyVolume — re-reads the volumes in storage and compares them with the catalog.The most useful mode for routine audits is VerifyCatalog: fast because it only compares path names and metadata, and sufficient for finding structural differences.
Job {
Name = "Verify Web"
Type = Verify
Level = VerifyCatalog
Client = client-fd
FileSet = "Set Web"
Storage = FileStorage
Pool = FilePool
}Run it from bconsole:
* run job="Verify Web" yes
* list jobs | grep VerifyThe Verify job output reports differences: files on the client that aren't in the catalog, or vice versa. If Termination: Verify OK without warnings, the catalog and reality are in sync.
Note
Verify consumes client and storage resources, so don't schedule it alongside a full backup. A common pattern: verify the catalog weekly after the last incremental, and a monthly VerifyInit for full checksum integrity.
Media health can be assessed from the volume list:
* list volumes
* list volumes pool=FilePoolWatch the status column: Append (can still be written), Full (complete), Recyclable (can be reused), Used (in use), and Purged (records deleted). Recyclable volumes are the next recycle targets.
With AutoPrune = yes on the pool, Bacula runs automatic prune when a job runs — volume records past retention are cleaned up and the volumes become Recyclable. If you see volumes piling up as Full without ever being recycled, check:
* show pool=FilePoolMake sure AutoPrune = yes, Recycle = yes, and Volume Retention isn't too long for your storage size.
Prune removes records that have already passed retention:
* pruneBacula offers targets: prune for a specific client, a specific volume, or everything. This is a safe operation — it only touches data that has genuinely expired.
Purge removes records regardless of retention — forced. Legitimate use cases:
list jobs isn't misleading.* purge jobid=12
* purge volume=FilePool-0003Danger
purge deletes records from the catalog but does not automatically delete the physical data on the volumes. After a purge, Bacula considers the volume reusable — if Recycle = yes, the old data will be overwritten. Before purging, ask: "Can I live without being able to restore this data?" If in doubt, don't purge.
A simple audit routine:
* list jobs | head -50
* list volumes
* status catalogWatch for repeated Error jobs, volumes growing abnormally, and Verify jobs reporting suspicious differences. All three are early signals of bigger problems.
Without the catalog, the data on the volumes still exists — but Bacula doesn't know which files are inside them. Per-file restore becomes impossible; you can only extract raw volumes. That's why the catalog must be backed up, usually more often than ordinary data (daily).
The Bacula package includes a dedicated FileSet for the catalog:
FileSet {
Name = "Catalog"
Include {
Options { signature = MD5 }
File = /var/lib/postgresql
File = /var/lib/bacula
}
}Job {
Name = "Backup Catalog"
Type = Backup
Level = Full
Client = bacula-fd
FileSet = "Catalog"
Schedule = "DailyAfterBackup"
Storage = FileStorage
Pool = FilePool
}Schedule it after all data backups finish, so the catalog records the latest state. With PostgreSQL, a cleaner alternative is pg_dump before the job — we practice this pre-hook pattern in episode 10.
Tip
Store the catalog backup on separate media from the data (a different pool, storage, or tape). If the main storage fails along with its catalog, a catalog backup on separate media is the only way to recover everything — episode 16 covers catalog recovery in full.
Key takeaways:
Verify jobs compare the client with the catalog; VerifyCatalog is a cheap routine audit.list volumes reveals media status; AutoPrune = yes keeps the recycle cycle moving.prune safely cleans up what's stale; purge forces things and must be used very carefully.In the next episode, episode 10, we'll back up databases and applications — the Enterprise plugin approach (Vmware, Hyper-V, MSSQL, MySQL/PostgreSQL agents, NDMP) versus the Community script-based approach with pre-backup and post-cleanup hooks, plus snapshot-based consistency strategies. This is where your backups get ready to protect the liveliest workloads.