Slow storage, networking and backup

How big should the SSDs in a ZFS special vdev be, and should you add one at all?

Sources checked · page updated · the question as people ask it: “I want to add a mirrored SSD special (metadata) vdev to my ZFS / TrueNAS / Proxmox hard-drive pool - how big do the SSDs need to be, what does special_small_blocks do, how do I measure what my pool would put there, and what happens if it fills up or fails?”

Quick answer

We found no OpenZFS, Proxmox or TrueNAS document that gives a sizing rule for a special vdev, so size it from your own pool: zdb's block statistics show how much metadata the pool holds and how much data sits in small blocks, and zpool list -v shows how full an existing special vdev is. By default only metadata goes there (special_small_blocks=0), small data blocks stop going there once its free space falls to 25% or less, and when it is full new allocations spill back to the hard drives. Mirror it at least as redundantly as the data vdevs, because the special vdev is a point of failure for the whole pool, and on a raidz or draid pool adding one cannot be undone.

What are you seeing?

Pick the closest symptom to open the matching diagnostic path. This is a guide to what to check and in what order; it does not read your system and does not diagnose it.

Measure what the special class would hold
  1. 1.Check the pool is the kind a special vdev is meant for. The Proxmox guide says a special device can improve the speed of a pool of slow spinning disks with a lot of metadata changes, and replies in one Level1Techs thread said the benefit is for spinning-disk pools. By default the special class takes all pool metadata, the indirect blocks of user data and any deduplication tables; small file and zvol blocks go there only if you opt in.
  2. 2.List what each dataset would send there today. special_small_blocks is the opt-in threshold for small data blocks; recordsize is the dataset's block size, and the two are read together.
    zfs get -r special_small_blocks,recordsize <pool>
    Readingspecial_small_blocks=0, the default, means only metadata would go to the special vdev. A value at or above a dataset's recordsize sends all of that dataset's data there. The SOURCE column shows whether a value is inherited from the pool's root dataset.
  3. 3.Read the pool's block statistics. zdb reads the pool devices directly from userspace; its man page warns that on an imported, active pool it may, though unlikely, interpret inconsistent pool data and behave erratically, so run it when the pool is quiet. -L skips leak detection and space map loading. TrueNAS forum posts add -U /data/zfs/zpool.cache, the zdb(8) option for a cache file other than /etc/zfs/zpool.cache.
    zdb -Lbbbs <pool>
    ReadingFrom -bb upwards zdb prints a per-type table (Blocks, LSIZE, PSIZE, ASIZE, avg, comp, %Total, Type) and a 'Block Size Histogram' whose psize, lsize and asize columns each give Count, Size and a cumulative Cum. total. The histogram comes from zdb.c; the zdb(8) man page we read does not describe it. The community sizing guide on the TrueNAS forums takes the metadata figure from the per-type table's L1 Total ASIZE and reads the asize Cum. value on the row for a candidate special_small_blocks size as the data that cutoff would send to the special class. That is a community method, not an OpenZFS formula.
  4. 4.Turn the two figures into a capacity. Add the metadata figure to the small-block figure for the cutoff you intend to set, or use the metadata figure alone if special_small_blocks will stay at 0. Then allow for the reserve in zfs(4): with zfs_special_class_metadata_reserve_pct at its default of 25, small data blocks are placed on the special and dedup vdevs only while their free space exceeds 25%, so once metadata and small blocks together fill three quarters of the mirror, further small blocks go to the hard drives.
    ReadingWe found no OpenZFS, Proxmox or TrueNAS document giving a sizing rule as a percentage of the pool or GB per TB, which is why this page measures rather than quoting one. A zdb estimate taken on blocks of one size can miss on blocks of another: in one Level1Techs thread zdb on the old pool, which used the default recordsize, suggested about 100GB, and after an rsync into the new pool, which was created with recordsize=1M, the special vdev held about 1.3GB. The histogram was measured on a different block-size population, and the thread did not resolve the discrepancy (see the third path).
Read an existing special vdev: how full, and with what
  1. 1.Check how full the special class is.
    zpool list -v <pool>
    ReadingPer-vdev rows with SIZE, ALLOC, FREE, FRAG and CAP. The zpool-list(8) example we read shows only a raidz1 pool; that the special mirror appears as its own row group comes from forum output. Its ALLOC and CAP are how full the special class is. By default small data blocks stop going there once its free space is 25% or less, and when it is full new allocations spill to the data vdevs. In one TrueNAS forum thread an 894G mirror beside 34.8T allocated on HDDs was 73.1% full.
  2. 2.Get the same figure from zdb: run the block statistics from the first path and find the 'Special class' line, which zdb prints when a special class exists.
    ReadingThe line gives the bytes allocated in the special class and 'used: N%'. A 'Dedup class' line follows when the pool has a dedup class.
  3. 3.If it is fuller than metadata explains, compare special_small_blocks with recordsize for each dataset, using the zfs get command from the first path. The Proxmox guide warns that a value greater than or equal to the dataset's recordsize writes all of that dataset's data to the special device. Placement follows the size of each block as written, not the dataset's current recordsize: blocks received by zfs send/receive keep the sizes they had on the source, so a threshold below the current recordsize can still catch them. A reply in the TrueNAS thread with the 73% full vdev also pointed out that the tail blocks of large files can qualify as small blocks.
    ReadingIn one Level1Techs thread the new pool was created with recordsize=1M and the receive used special_small_blocks=512K, below that recordsize, yet a zfs send/receive put almost all of the data on the special vdev. Replies said send/receive keeps the source's block sizes, and the source pool used the default recordsize.
  4. 4.To stop a dataset sending data blocks there, lower its threshold or set it to 0. The two documents disagree on the boundary and the range, so we print both: OpenZFS's zfsprops(7) says blocks smaller than or equal to the value, after compression and encryption, go to the special class, with values up to 16 MiB on the current man page; the Proxmox guide says blocks smaller than the value, with a power of two from 512B to 1M.
    zfs set special_small_blocks=0 <pool>/<dataset>
    ReadingProxmox's wording covers new file blocks. We found no OpenZFS, Proxmox or TrueNAS document stating what happens to blocks already on the special vdev when the value changes.
Data stayed on the hard drives after adding the vdev or changing the value
  1. 1.Start from what the documents say. The Proxmox guide says that after the property is set, new file blocks smaller than the size are allocated on the special device. We found no OpenZFS, Proxmox or TrueNAS document stating that blocks already written stay where they are when special_small_blocks changes, or that they move. The 'new file blocks' wording is the closest any of them comes.
  2. 2.Do not count on zfs rewrite to move data onto the special vdev. The zfs-rewrite(8) page we read says it rewrites blocks as is at a new location, possibly with new properties, and that changes to properties affecting logical block size, such as recordsize, have no effect. It does not mention special_small_blocks or the special class. In one Level1Techs thread, an owner set special_small_blocks=64K and ran zfs rewrite -rv, and the special vdev reached about 23G against an estimated 75G; a reply said new vdevs generally receive only new writes, and the thread ended unresolved.
  3. 3.Know how the copy method changed the outcome in one forum case. On a raidz1 pool with recordsize 1M, an rsync at special_small_blocks=64K put about 1.3GB on the special vdev; a zfs send/receive at 512K then put almost all of the data there. Replies explained that send/receive keeps the source's block sizes while rsync re-blocks the files, and an rsync into new datasets at 512K worked for the owner. That is one thread's experience, not a documented migration method.
Add a special mirror: redundancy, permanence and spares
  1. 1.Set the redundancy first. zpoolconcepts(7) says the special device's redundancy should match or exceed that of the pool's normal devices. The Proxmox guide calls it a point of failure for the whole pool, and TrueNAS says that if it fails with no redundancy the pool is corrupted and its data cannot be reached. TrueNAS's development documentation for TrueNAS 28 gives the pairing: a RAIDZ2 data vdev takes a RAIDZ2 or three-way-mirror metadata vdev, and pool creation fails when the metadata vdev is less redundant. At the command line, zpool add has -f and --allow-replication-mismatch, which accept a conflicting replication level; neither changes what a failed special vdev costs.
  2. 2.Check whether you could take it out again, because the documents disagree. OpenZFS's zpool-remove(8) removes a special vdev only when the pool's primary storage has no raidz or draid top-level vdev, every top-level vdev shares one ashift, encryption keys are loaded and the device_removal feature is enabled. TrueNAS 25.04 says a metadata vdev on a RAIDZ pool is a permanent addition, removable only when the data vdevs are mirrors. The Proxmox guide says, with no conditions, 'Adding a special device to a pool cannot be undone'. zpool-add(8) adds that top-level vdevs with different sector sizes prohibit future removal.
    ReadingOn a raidz pool all three agree it stays; zpool-remove(8) also rules out draid. Two forum sources also report that a special vdev could not be replaced with smaller devices, one quoting the error 'device is too small'.
  3. 3.Do not plan on a hot spare for it without checking your TrueNAS version. The 25.04 documentation suggests mirroring metadata vdevs and optionally adding hot spares; the TrueNAS 28 development documentation says hot spares only activate in data vdevs, so a hot spare cannot replace a failed drive in a special vdev.
  4. 4.Pick the SSDs. The Proxmox guide says to use fast SSDs for the special device. TrueNAS 28 documentation says that when the SSDs have an internal cache, a UPS helps minimise the risk from power loss. OpenZFS defines adequate power-loss protection as protecting the drive's own metadata and all flushed data, and says hardware power-loss protection is a feature of enterprise SSDs. We found no OpenZFS, Proxmox or TrueNAS document stating an endurance (DWPD or TBW) or power-loss protection requirement specifically for a special vdev.
  5. 5.Add the mirror. This is irreversible on any pool with raidz or draid data vdevs, and from then on the special vdev is a point of failure for the whole pool: lose it without redundancy and you lose the pool and its data. The pool must already have at least one normal data vdev. Name three devices after 'mirror' where the data vdevs are RAIDZ2, per the TrueNAS pairing above.
    Destructive. This command destroys what is on the device and cannot be undone. Confirm the device path twice and have a backup of anything you still need before running it.
    zpool add <pool> special mirror <dev1> <dev2>
    ReadingThis is the form the Proxmox guide documents. In the one forum report in the third path where a special vdev was added to a pool already holding data (t5), a reply said new vdevs generally receive only new writes, and even after zfs rewrite the vdev held about 23G against an estimated 75G. New metadata, and new small blocks once you opt in, go to it.
  6. 6.If your measurement supports a small-block cutoff, set it per dataset. zfsprops(7) says a special class vdev must be added to the pool before this property is set. Keep the value below the dataset's recordsize unless you mean to put the whole dataset on the SSDs.
    zfs set special_small_blocks=<size> <pool>/<dataset>
    ReadingIn a TrueNAS forum thread about photo and video editing on two 4-wide RAIDZ1 vdevs, replies suggested recordsize=1M with special_small_blocks=512K and a three-way special mirror for RAIDZ2; no outcome was posted.

Causes, how to confirm each, and whether hardware fixes it

CauseHow to confirmFixHardware?
Metadata, indirect blocks and dedup tables fill the special vdev while special_small_blocks is still 0zpool list -v shows the special mirror's CAP climbing and zfs get shows special_small_blocks=0 on every dataset. zdb -Lbbbs --class=special <pool> limits the per-type table to blocks in the special class; without --class the table covers the whole poolThese are default placements (zfs(4) lists the module parameters behind DDT and indirect-block placement). Size the mirror from the measured metadata, or add a second special mirror at the same redundancy: zpoolconcepts(7) load-balances multiple special devicesYes
special_small_blocks at or above the size of a dataset's blockszfs get -r special_small_blocks,recordsize shows the threshold equal to or larger than recordsize on the dataset whose data moved to the SSDs. zfs get alone can miss it: placement follows the size of each block as written, and blocks received by zfs send/receive keep the source's sizes, so a threshold below the current recordsize can still catch themSet the threshold below the block size the dataset's data was written at, or to 0, for that dataset. Proxmox's wording covers new file blocks; no document we read says blocks already placed move backNo
The special class is full or inside its 25% reservezpool list -v shows the special mirror's CAP at 75% or more, or zdb's 'Special class' line shows the same; past that point small data blocks go to the hard drives, and once it is full metadata allocations spill back tooLower special_small_blocks on datasets that do not need it, or add another special mirror with the same redundancyYes
Data written before the vdev or the setting is still on the hard drivesThe special vdev's ALLOC stays well below the zdb estimate after a zfs rewrite, or after a file-level copy such as rsync into a dataset with a larger recordsizeNo document we read describes moving existing blocks onto a special vdev. In one forum case a file-level copy into new datasets placed data by the new setting; zfs rewrite did not in anotherNo
A planned special mirror less redundant than the data vdevszpool list -v shows the data vdevs' layout, for example RAIDZ2, beside a planned two-drive special mirrorBuy enough identical drives to match before adding: TrueNAS pairs RAIDZ2 data with a RAIDZ2 or three-way-mirror metadata vdev. On a pool where it is already added, the zpool-remove(8) conditions decide whether it can come outYes
If your measurement says a special mirror will help: small enterprise SSDs

The live list is SSDs of 3.84TB or less with a stated DWPD or TBW, filtered on an enterprise form factor (U.2, U.3, E1.S, E3.S) or a SAS interface; that filter is the catalogue's class proxy, a stored field rather than a test, and no document we read names it. The DWPD or TBW filter only removes listings whose rating cannot be compared with your measured writes; no document we read sets an endurance requirement for a special vdev. Metadata changes, and intent-log traffic on a pool without a log device, are why those writes are worth measuring: the wearout page measures them and the endurance calculator turns them into a rating. The 3.84TB ceiling is a catalogue cut, not a sizing rule: a 1.92TB ceiling left only three in-stock rows, so the list stops at 3.84TB, and your zdb figure plus the 25% reserve decides what you actually need. Buy identical drives as a set, two for a mirror or three where the data vdevs are RAIDZ2, because the catalogue cannot pair listings as a mirror; we store no power-loss protection or latency column, so check both in each model's own document, and match the interface to a free bay and controller in your host.

When not to buy: Do not buy when zdb shows the pool's metadata and small blocks are a small fraction of it and the pool is already fast enough for its work, or when the pool is raidz and you are not ready for a permanent addition: on raidz or draid the special vdev cannot be removed, and losing it loses the pool.

Every row below meets: SSD (not PS5-SSD or SATA-SSD) · Enterprise form factor: U.2, U.3, E1.S or E3.S · or a SAS interface · Stated endurance: DWPD (so the rating can be set against your measured writes) · or stated endurance: TBW (so the rating can be set against your measured writes) · Small capacity: 3.84TB or less. A listing whose field is not stated is excluded from a required criterion and marked “not stated” on an optional one; nothing is assumed. What the catalogue cannot evaluate: power-loss protection (PLP); latency; mirror pairing / redundancy level. Check these on the maker's data sheet.
Product · part numberCap.Interface · form · ratingConditionPrice$/TBBuy
Samsung PM9A3 960GB U.2 NVMe
MZQL2960HCJR · details
0.96TBNVMe-PCIe4 · U.2 · 1 DWPDNEW Amazon: New / Unknown · sold by DiscTech (USA)$798.00$831.25Buy on Amazon
Dell 3.84TB SAS SSD Read Intensive 12G
MZILT3T8HBLS · details
3.84TBSAS-12G · 2.5" · 0.8 DWPDREFURB / USED Amazon: Used / LikeNew · sold by Tech on Time (SN RECORDED)$799.99$208.33Buy on Amazon
Micron 7450 PRO 3.84TB U.3
MTFDKCC3T8TFS · details
3.84TBNVMe-PCIe4 · U.3 · 1 DWPDREFURB / USED Amazon: Used / LikeNew · sold by CorteseInc$1,990.00$518.23Buy on Amazon
Samsung PM1643A 1.92TB SAS SSD
MZILT1T9HBJR · details
1.92TBSAS-12G · 2.5" · 1 DWPDNEW Amazon: New / Unknown · sold by SiliconValleySeller (SN# Recorded)$2,095.00$1,091.15Buy on Amazon
Samsung PM1643a 1.92TB SAS SSD
MZILT1T9HBJR-00007 · details
1.92TBSAS-12G · 2.5" · 1 DWPDNEW Amazon: New / Unknown · sold by SiliconValleySeller (SN# Recorded)$2,145.00$1,117.19Buy on Amazon
Micron 7600 PRO 3.84TB U.2 PCIe5
MTFDLAL3T8THG · details
3.84TBNVMe-PCIe5 · U.2 · 1 DWPDNEW Amazon: New / Unknown · sold by Hard2FindParts$2,599.00$676.82Buy on Amazon
Tracked, currently unavailable

Prices are Amazon US, re-checked about once a day; newest price in this table . A click here is a click, not a purchase; we earn a commission on qualifying purchases. The table shows what the catalogue holds against the criteria, not an endorsement of any model for your server.

Read next on this site

Frequently asked questions

Is there a percentage of pool size I can use instead of measuring?

Not from any OpenZFS, Proxmox or TrueNAS document we read. Forum figures are anecdotes and spread widely: in one ServeTheHome thread replies offered about 0.3% of the pool for metadata, 3-5%, and about 10% with small blocks, with no formula agreed; in another, a 121T pool 47% full had 38.7G on a three-way mirror of about 932G SSDs, 38.7G being 4.17% of the special mirror's own capacity; on Level1Techs one reply sized from its own histogram at about 35GB of sub-1M blocks on a 42.7TB pool. Measure your own pool with zdb instead.

Does the special vdev also take the ZFS intent log?

zpoolconcepts(7) lists the intent log among what the special class holds when the pool has no separate log device. zfs(4) has zil_special_is_slog, default 1: when it is enabled and written blocks go to normal vdevs, present special vdevs are treated as SLOGs, and the parameter is ignored if a SLOG is present. Its sync-write traffic is therefore part of what the SSDs see on a pool without a log device.

Can I swap the special mirror for smaller SSDs later?

We found no OpenZFS, Proxmox or TrueNAS document covering replacement with smaller drives. Two forum sources report that it fails: a Level1Techs poster got 'device is too small', and the TrueNAS community sizing guide says a special vdev cannot be replaced with smaller drives. Whether the vdev can be removed instead depends on the zpool-remove(8) conditions, which rule out any pool with raidz or draid data vdevs.

Does dedup change the sizing?

Deduplication tables go to the special class by default: zpoolconcepts(7) lists them, and zfs(4) has zfs_ddt_data_is_special, default 1. A pool using dedup therefore puts its tables on the special vdev too, unless the pool has a separate dedup vdev, and zfs(4) applies the same 25% small-block reserve to dedup vdevs as to special ones.

Sources

Every technical statement above rests on one of these documents, each read on the date shown. Where a document did not state something, the page says so rather than filling the gap.

  1. zpoolconcepts(7) - Virtual Devices (special, dedup) and Special Allocation Class · checked
  2. zfsprops(7) - special_small_blocks · checked
  3. zpool-remove(8) · checked
  4. zdb(8) · checked
  5. cmd/zdb/zdb.c (master) - dump_block_stats / dump_size_histograms · checked
  6. zfs(4) - module parameters · checked
  7. zpool-list(8) · checked
  8. Proxmox VE Administration Guide - ZFS on Linux > ZFS Special Device · checked
  9. TrueNAS 25.04 documentation - Fusion Pools · checked
  10. TrueNAS 28 (Early / development) documentation - Creating Fusion Pools · checked
  11. OpenZFS Performance and Tuning: Hardware - NAND Flash SSDs > Power Failure Protection · checked
  12. zpool-add(8) · checked
  13. zfs-rewrite(8) · checked

Where people hit this

Discussions we opened and read while researching this page. They are evidence that the problem occurs and of what people tried; no specification above is sourced to a forum post.

Other slow storage, networking and backup problems

Share:WhatsAppFacebookPost on X