VDI on Windows, TDS/FIFO on Linux, BACKUP TO URL for Azure SQL MI, up-to-64-way striped parallel I/O, three native replication modes (log shipping / AG bootstrap / fanout), instant recovery, and SSAS/SSRS/SSIS coverage.
Technical companion to the PodHeitor MSSQL plugin page.
1. The problem: Bacula Enterprise’s MSSQL plugin is Windows-only and single-stripe
Bacula Enterprise’s MSSQL plugin exists, but:
- Windows-only with VDI — no SQL Server on Linux coverage (officially Microsoft-supported since 2017).
- No striped parallel I/O — 1 TB+ VLDBs suffer with single-stream throughput.
- No Always On AG awareness beyond the basics — no auto-selection of readable secondary, no AG reseed.
- No native replication — log shipping, AG bootstrap and 1→N fanout require external scripting.
- No instant recovery, single-item restore, or SSAS/SSRS/SSIS coverage.
The PodHeitor MSSQL Plugin delivers all of that and stays drop-in compatible with the Bacula Enterprise mssql-fd namespace — zero FileSet rewrites in migration.
2. Architectural model
PodHeitor pattern: FD cdylib + standalone backend, PTCOMM communication. On Windows the cdylib is a DLL (podheitor-mssql-fd.dll); on Linux it’s a .so.
v2.0.0 (May 2026): the cdylib is built as a pure-Rust cdylib from the PodHeitor Rust cdylib/crates/plugin-mssql/ workspace. No Bacula AGPLv3 source is statically linked anywhere in the build — the plugin is fully proprietary (LicenseRef-PodHeitor-Proprietary). The v1.0.0 C/C++ metaplugin shim has been archived under releases/v1.0.0/src/ for historical reference only and is no longer built.
3. Engines selectable via mode=
| Mode | Platform | Function |
|---|---|---|
auto (default) |
— | Detects platform; prefers VDI on Windows, TDS/FIFO on Linux |
vdi |
Windows | Virtual Device Interface — official Microsoft API, in-memory pipe |
tds_fifo |
Linux/Windows | BACKUP DATABASE TO DISK = ‘<FIFO>’ over TDS, mkfifo reads stream |
tds_url |
— | BACKUP TO URL to Azure Blob (Azure SQL Managed Instance) |
snapshot |
Windows | VSS Snapshot |
replicate_log_shipping |
— | Replication via native log shipping |
replicate_ag_bootstrap |
— | Bootstrap of Always On AG secondary |
replicate_fanout |
— | 1→N region replication |
4. Striped parallel I/O
BACKUP DATABASE ... TO DISK = '...stripe-1', DISK = '...stripe-2', ... is the SQL Server feature for multi-target. Bacula Enterprise does not expose it; PodHeitor does, via the stripes=N parameter (1–64). On a 1 TB VLDB with stripes=8, observed throughput is ~4× single-stream. Combine with buffercount=32 and maxtransfersize=4194304 (4 MiB) to saturate storage I/O.
Plugin = "podheitor-mssql: database=warehouse stripes=8 parallel_dbs=2
compress=native+zstd buffercount=32 maxtransfersize=4194304"
5. Always On AG awareness
With ag_preference=readable_secondary, the plugin:
- Queries AG topology via
sys.dm_hadr_availability_replica_states. - Selects a readable secondary (offload primary).
- If the chosen secondary fails/rebalances during backup, retries automatically on another replica up to
ag_failover_retry=3attempts. - Topology is captured in
__ph_cluster__/ag_topology.jsonfor post-restore AG reseed.
Other options: auto, primary, secondary, readable_secondary.
6. Instant Recovery + Single-Item Restore
| Restore mode | Function |
|---|---|
instant |
DB queryable in minutes while restore continues in background |
in_place |
Over-write restore on the original DB |
new_db |
Restore with new name (rename via database=) |
to_disk |
Restore to .bak file (no SQL Server import) |
single_item |
Table/row extraction via ephemeral sandbox instance |
ag_reseed |
AG secondary reseed from backup |
single_item spawns a temporary sandbox SQL Server instance, restores the DB there, runs SELECT or BCP OUT to extract the requested rows, and discards the sandbox. Useful when “I need the Orders table from yesterday” is not worth the in-place restore downtime.
7. PITR (Point-in-Time Recovery)
| Parameter | Default | Function |
|---|---|---|
stop_at |
— | PITR datetime (e.g., 2026-04-25 15:30:00) |
stop_at_mark |
— | PITR log mark |
tail_log_before |
no | Auto-capture tail-log before tearing down existing DB |
file_relocation_map |
— | JSON with path mapping for cross-instance restore |
tde_restore_cert |
— | TDE cert bundle for cross-server |
recovery |
Yes | WITH RECOVERY (final) vs NORECOVERY (chain) |
8. BI server coverage
| Server | Mechanism | Parameter |
|---|---|---|
| SSAS (Analysis Services) | Native XMLA backup | include_ssas=<list> |
| SSRS (Reporting Services) | ReportServer DB backup + encryption keys | include_ssrs=<host:port> |
| SSIS (Integration Services) | SSISDB backup | include_ssis=yes |
9. TDE-aware cross-server restore
TDE (Transparent Data Encryption) requires the master cert + the instance’s DPAPI to open an encrypted DB. Without it, cross-server restore fails with Cannot find server certificate with thumbprint. PodHeitor with tde_capture=yes exports the cert + private key (encrypted with an operational password) during backup; on restore, tde_restore_cert=<file> reinstalls the cert before the DB restore. This unlocks cross-instance / cross-region restore with no manual intervention.
10. GA validation — v1.0.0
| Metric | Result |
|---|---|
| E2E test suite (T01–T13, 16 tests) | 16 / 16 PASS (3 consecutive runs) |
| OL9 cargo test | 311 passed, 0 failed |
| Win2025 cargo test | 381 passed, 0 failed |
| SQL Server tested | SQL Server 2022 on Windows Server 2025 |
| AG configuration | 2-node, CLUSTER_TYPE=NONE, SYNCHRONOUS_COMMIT |
| Bacula version | Community 15.0.3 |
| Packages | RPM v1.0.0 (OL9) + Win64 zip v1.0.0 |
11. Supported platforms
| OS | Arch | Status |
|---|---|---|
| Windows Server 2012 R2 – 2025 | x86_64 | GA |
| Oracle Linux 9, RHEL 8/9, Rocky/Alma 8/9 | x86_64 | GA |
| Ubuntu 20.04 / 22.04 / 24.04 | x86_64 | GA |
| Debian 11 / 12 | x86_64 | GA |
| Linux ARM64 | aarch64 | Roadmap v1.1 |
| SQL Server | Windows | Linux | Notes |
|---|---|---|---|
| 2012, 2014 | VDI | — | Windows only |
| 2016, 2017 | VDI | TDS/FIFO | — |
| 2019, 2022 | All modes | TDS/FIFO | — |
| Azure SQL MI | — | tds_url | BACKUP TO URL |
12. Drop-in Enterprise migration
The Bacula namespace is identical to that of Bacula Enterprise’s mssql-fd.dll:
@mssql/
├── MSSQLSERVER/
│ ├── AdventureWorks/
│ │ ├── data.bak ← Full backup
│ │ ├── data.diff.bak ← Differential
│ │ ├── log-<LSN>.trn ← Transaction log
│ │ ├── layout.dat ← DB layout RestoreObject
│ │ └── data.stripe-N.bak ← When stripes > 1
│ └── __ph_instance__/ ← PodHeitor extras (logins, jobs, config)
└── __ph_cluster__/
└── ag_topology.json
Migrating from Enterprise to PodHeitor doesn’t require rewriting FileSets or Bacula Director jobs — just swap the binary.
13. Documented anti-patterns
- Don’t run
stripes=64on a small DB. Coordination overhead exceeds gains; for DBs < 50 GB usestripes=4or less. - Don’t combine
tail_log_before=yeswith absent-mindeddrop_existing=yes. Order matters: tail-log captures BEFORE drop, butdrop_existing=only_if_matchis safer in prod. - Don’t use
compress=noneover WAN. SQL Server native compression + zstd dramatically reduces bytes-on-wire; the CPU overhead is worth it. - Don’t run TDS/FIFO on Windows when VDI is available. VDI is the official Microsoft API with better throughput and VSS integration; TDS/FIFO exists as the Linux fallback.
14. License posture
Plugin under LicenseRef-PodHeitor-Proprietary. No Bacula AGPLv3 source is statically linked anywhere in the build in v2.0.0+. The cdylib is built from the pure-PodHeitor plugin-mssql crate.
Ready to evaluate?
30-day free trial for production SQL Server fleets (Windows + Linux + Azure SQL MI). Guaranteed at minimum 50% discount vs Bacula Enterprise, Veeam or Commvault, with more capabilities included (3 native replication modes, instant recovery, single-item restore, SSAS/SSRS/SSIS coverage).
Heitor Faria — Founder, PodHeitor International
✉ [email protected]
☎ +1 (789) 726-1749 · +55 (61) 98268-4220 (WhatsApp)
🔗 PodHeitor MSSQL plugin page
Disponível em:
Português (Portuguese (Brazil))
English
Español (Spanish)