Proxmox RAIDZ Expansion Grows Your ZFS Pool One Disk
Proxmox RAIDZ expansion in PVE 9 grows a ZFS pool one disk at a time online with zpool attach — commands, reflow monitoring, and the rebalance fix for full capacity.
On this page
Yes, Proxmox VE 9 can finally grow a RAIDZ pool one disk at a time — no backup, destroy, and restore dance required. ZFS 2.3 (shipped in PVE 9.0) added RAIDZ expansion, so a zpool attach widens an existing raidz1/2/3 vdev while the pool stays online and your VMs keep running. The concrete outcome: a 4-disk raidz1 becomes a 5-disk raidz1 in place, with the one honest catch being that old data keeps its original parity ratio until you rewrite it.
Key Takeaways
- Version: RAIDZ expansion needs ZFS 2.3, which ships in Proxmox VE 9.0 — confirm
feature@raidz_expansionisenabledoractivebefore you start. - Command: You grow a vdev with a single
zpool attach <pool> <vdev> /dev/disk/by-id/<newdisk>— always by-id, never/dev/sdX. - Online: Expansion runs live as a background reflow; track it with
zpool statusand it completes in hours, not minutes. - The catch: Pre-existing data keeps its old data:parity ratio, so you will not see full new capacity until that data is rewritten.
- The limit: One disk per operation into one existing vdev — raidz1 stays raidz1, and
ashiftnever changes.
What RAIDZ expansion actually does in Proxmox VE 9
For years, growing a RAIDZ vdev meant one of two ugly paths: back everything up, destroy the pool, recreate it wider, and restore — or bolt on a second full vdev and eat the extra parity overhead. RAIDZ expansion (OpenZFS feature raidz_expansion, merged in ZFS 2.3) kills the first problem. You attach a single disk to an existing raidz vdev and ZFS performs a reflow: it walks every allocated block and rewrites it across the wider stripe, all while the pool serves reads and writes.
Proxmox VE 9.0 was the release that pulled ZFS 2.3 into the default kernel module. If you are still on PVE 8.x (ZFS 2.2), the feature does not exist — no amount of CLI coaxing will conjure it. So step one is always a version and feature check. If you are new to ZFS pool layout on Proxmox, the groundwork in Setting Up ZFS on Proxmox: Pools, Datasets, and Best Practices is worth reading first, because expansion assumes you already understand vdevs versus pools.
# Confirm your ZFS module version (expect 2.3.x or newer)
zfs version
# Check the feature flag on the target pool
zpool get feature@raidz_expansion tank
You want output like this:
NAME PROPERTY VALUE SOURCE
tank feature@raidz_expansion enabled local
enabled means the feature is present but no expansion has happened yet; it flips to active after your first expand. If you see disabled, upgrade the pool's feature flags with zpool upgrade tank — but understand that once you do, the pool can no longer be imported by older ZFS releases, so don't upgrade a pool you might need to roll back.
How to grow a RAIDZ vdev one disk at a time
Here is the whole procedure on a real 4-wide raidz1 pool named tank. Start by identifying the pool topology so you attach to the correct vdev, not to the pool root.
zpool status tank
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz1-0 ONLINE 0 0 0
ata-WDC_WD40EFPX-0001 ONLINE 0 0 0
ata-WDC_WD40EFPX-0002 ONLINE 0 0 0
ata-WDC_WD40EFPX-0003 ONLINE 0 0 0
ata-WDC_WD40EFPX-0004 ONLINE 0 0 0
The vdev you attach to is raidz1-0 — the internal vdev name, not tank. Now find the stable identifier for the new disk. This is the part people get wrong: /dev/sdX names are assigned by probe order and will shuffle across reboots, which is how you end up attaching the wrong device or breaking an import later. Use /dev/disk/by-id/ every single time.
ls -l /dev/disk/by-id/ | grep -v part
Pick the WWN or model-serial link for the fresh drive, then run the expansion:
# Grow raidz1-0 from 4 disks to 5, online
zpool attach tank raidz1-0 /dev/disk/by-id/ata-WDC_WD40EFPX-0005
That is it. The command returns almost immediately, but the real work — the reflow — now runs in the background. On a pool with a few terabytes of allocated data on 5400 RPM spinners, expect the reflow to take several hours to a day; a lightly used 4 TB pool typically finishes in the 4-8 hour range. The pool is fully usable throughout, though sequential throughput will dip while the reflow saturates the disks.
Monitoring the reflow to completion
zpool status shows an expansion line while the reflow runs. Poll it, or watch it live:
# One-shot
zpool status tank
# Live, refresh every 5 seconds
watch -n5 zpool status tank
Mid-reflow you will see something like:
pool: tank
state: ONLINE
scan: none requested
expand: expansion of raidz1-0 in progress since Wed Jul 9 10:14:22 2026
1.31T / 3.02T copied at 412M/s, 43.38% done, 01:12:44 to go
config:
NAME STATE READ WRITE CKSUM
raidz1-0 ONLINE 0 0 0
...
ata-WDC_WD40EFPX-0005 ONLINE 0 0 0
When it finishes, the expand: line reports completion, and zpool status -v confirms the wider geometry with no errors:
zpool status -v tank
Do not reboot mid-reflow if you can avoid it. The reflow is crash-safe and will resume after an unclean shutdown, but you gain nothing by interrupting it and you extend the window where the pool runs degraded in throughput.
Why you don't get full capacity back immediately
Here is the caveat that trips up everyone the first time, and it is the reason you must plan an expansion rather than treat it as free space. RAIDZ expansion does not re-stripe existing data to the new parity ratio. It relocates old blocks onto the wider set of disks, but each old block keeps the data:parity layout it was written with.
Concretely: a 4-disk raidz1 stores data at a 3:1 ratio (three data columns per one parity column). Grow it to 5 disks and new writes use a 4:1 ratio — better efficiency, more usable space per byte written. But every block that existed before the expansion is still accounted at 3:1. zpool list will show the raw capacity increase from the new disk, yet your usable-after-parity gain on already-written data is smaller than the disk's full size until that data is rewritten.
# Raw pool size grows immediately...
zpool list tank
# ...but df/used reflects the old ratio for pre-existing data
zfs list tank
This is expected behavior, not a bug, and OpenZFS documents it plainly. If your pool was nearly full of cold archival data, a single-disk expand buys you less immediate breathing room than the arithmetic suggests. Understanding how ZFS reports space here connects directly to the capacity-planning discipline in Optimizing ZFS Pools in Proxmox VE: Storage Tuning Guide.
The rebalance workaround: rewrite to realize the new ratio
To actually claim the improved efficiency, you have to rewrite the data so it lands at the new parity ratio. There is no built-in "rebalance" button in ZFS — you force it. Two practical approaches:
Option A — send/recv into a fresh dataset. This is the clean, atomic way. Snapshot the dataset, zfs send it into a new dataset on the same pool, verify, then swap.
# Snapshot, then stream into a new dataset that inherits the new ratio
zfs snapshot tank/vmdata@rebalance
zfs send tank/vmdata@rebalance | zfs recv tank/vmdata_new
# Verify the copy, then retire the old dataset and rename
zfs destroy -r tank/vmdata
zfs rename tank/vmdata_new tank/vmdata
Stop the VMs or containers using that dataset before the final destroy/rename so nothing is writing during the swap.
Option B — rewrite files in place. For a dataset full of loose files, copying each file over itself forces reallocation. A common one-liner uses a rebalancing script that copies each file to a temp name and moves it back, preserving permissions. It is cruder and not atomic, so it suits media libraries more than live VM disks.
Either way, only rewritten data benefits. Cold data you never touch stays at the old ratio forever, which is usually fine — you are not losing anything, you are just not gaining the theoretical maximum.
When a single-disk expand is the wrong call
RAIDZ expansion is a scalpel, not a hammer. It is ideal when you have one free bay and want incremental growth on the same fault domain. It is the wrong tool in a few cases:
| Situation | Better choice | Why |
|---|---|---|
| You want more IOPS, not just space | Add a second vdev | Each vdev adds parallelism; expanding one vdev does not |
| You need to change raidz1 → raidz2 | Destroy and recreate | Expansion cannot change the parity level |
| You have several disks to add at once | Add a whole new vdev | You can only attach one disk per expand operation |
| Pool is full of cold data you won't rewrite | Reconsider — gains are limited | Old blocks keep the old ratio |
Two hard limits are worth restating. First, you add exactly one disk per operation to one existing vdev — there is no batch expand, and you cannot promote raidz1 to raidz2. Second, ashift is fixed at vdev creation and expansion does not change it; if your original vdev was built with the wrong ashift, expansion will not fix that, and you should read up on the implications in ZFS vs Ceph on Proxmox: Which Cluster Storage Should You Run? if you are weighing whether to stay on ZFS at all for a growing cluster.
Also keep resilience in mind: widening a raidz1 from 4 to 6 disks increases the probability that a second disk fails during a rebuild while still only tolerating a single failure. Past five or six data disks, a raidz2 layout is the more defensible design, and no amount of expansion converts you to it after the fact. For pools where you are tuning for performance rather than raw capacity, the caching and log-device guidance in Proxmox ZFS Tuning: ARC, L2ARC, and SLOG Guide often matters more than adding another spindle.
A realistic gotcha from the field
The most common real-world snag is not the expand command — it is bay and cabling assumptions. On one homelab box, a newly attached disk showed up fine under by-id, the reflow started, and then throughput cratered to under 50 MB/s. The cause was a shared SATA port multiplier feeding the new drive, so the reflow was bottlenecked on a link the other four disks did not share. The fix was moving the disk to a direct HBA port; the reflow immediately jumped back to ~400 MB/s. The lesson: an expansion is only as fast as the slowest new path, so seat the new disk on the same class of controller as the rest of the vdev before you attach it.
The honest tradeoff for the whole feature: RAIDZ expansion trades simplicity of growth for deferred efficiency. You get painless, online, one-disk-at-a-time growth, but you accept that reclaiming full parity efficiency on old data is a manual rewrite you have to schedule. For most homelab and small-cluster pools, that trade is well worth it — the alternative was a full backup-and-restore outage.
Conclusion
RAIDZ expansion in Proxmox VE 9 turns growing a ZFS pool from a weekend project into a one-line, online operation: verify feature@raidz_expansion, zpool attach the new disk by its by-id path, and watch the reflow finish in zpool status. Just remember the parity-ratio caveat and plan a zfs send | zfs recv rebalance if you want to realize the full efficiency gain on existing data. Your next step: confirm you are on ZFS 2.3+ with zfs version, identify the disk you will add, and schedule the reflow for a low-traffic window.