Your Proxmox VE host is running on a fast NVMe drive or a ZFS mirror of SSDs, but the virtual machines sitting on top of it don't automatically know that. By default, a guest OS deletes a file, marks the blocks as free in its own filesystem, and never tells the underlying storage anything about it. Proxmox still thinks those blocks are in use. Over months of normal use, thin-provisioned storage can end up holding onto gigabytes of data that technically doesn't exist anymore.
That's what Discard and TRIM are for. This tutorial walks you through turning them on for a VM disk in Proxmox VE, what's happening underneath the checkbox, and the handful of gotchas that trip up almost everyone the first time.
What You Will Learn
You'll learn what the Discard and SSD Emulation options actually do on a VM's hard disk, and why neither one does anything by itself without the other pieces in place. We'll enable Discard on an existing disk through the web interface and from the command line with qm set, then configure the guest OS to actually send TRIM commands on a schedule using fstrim.timer. If your storage is ZFS, you'll also see how pool-level autotrim fits into the picture and why it's not always the setting you want.
Along the way I'll point out the storage types where this doesn't apply at all, because turning on a checkbox that silently does nothing is worse than not having the option.
What Is This Feature?
TRIM is a command that a filesystem sends to a storage device to say "these blocks are free, you don't need to preserve their contents." SSDs use this to plan garbage collection and keep write performance from degrading over time. Spinning hard drives don't need it, which is why the option in Proxmox is really about telling the storage layer to honor those TRIM requests, not about the physical disk type.
In Proxmox, this shows up as two separate checkboxes on a VM's hard disk:
- Discard — lets the guest OS send TRIM/UNMAP commands through to the underlying Proxmox storage. When a file is deleted inside the VM, the freed blocks get released on the host side too, shrinking a thin-provisioned disk image instead of letting it grow forever.
- SSD Emulation — makes the virtual disk report itself to the guest as a solid-state drive, even if the physical storage isn't SSD at all. Some guest operating systems, mainly older Windows builds, only bother scheduling TRIM maintenance if they believe the disk is an SSD.
Both settings only matter on thin-provisioned storage. Thin provisioning means the storage backend allocates space as data is actually written, rather than reserving the full disk size up front. ZFS, LVM-thin, Ceph RBD, and qcow2 files on directory storage are all thin-provisioned. A plain LVM volume group without thin pools is not — it allocates the entire disk size immediately, so there's nothing for Discard to reclaim, and Proxmox will grey the checkbox out.
Why Would You Use It?
The most obvious reason is disk space. I've seen a 32 GB Windows VM balloon its qcow2 image file to 30-something GB after a year of Windows Updates writing and deleting temp files, even though the actual data inside the VM was under 15 GB. With Discard enabled and the guest trimming regularly, that image shrinks back down as space is freed.
The second reason is SSD longevity and write performance. Every write to a NAND SSD that lands on a block the drive thinks is still "in use" costs more than it should, because the drive has to read, erase, and rewrite instead of just writing to a block it already knows is empty. On a homelab box with a single consumer SSD, that difference is noticeable after a year or two of heavy VM churn — snapshots, template clones, log rotation, all of it.
None of this matters much if your storage is a spinning HDD array or if your VMs barely touch disk. If you're running a couple of lightweight LXC containers on a NAS-grade array, don't bother. If you're running Windows VMs on a single consumer NVMe drive that's already half full, this is worth ten minutes of your time.
Prerequisites
Before you start, make sure you have:
- A Proxmox VE host, ideally 8.x or 9.x, though this has worked the same way for several major versions.
- Root or an account with
VM.Config.Diskpermission on the VM you're editing. - Storage that actually supports thin provisioning — ZFS, LVM-thin, Ceph, or a directory/NFS storage using qcow2. Check Datacenter → Storage and look at the Type column if you're not sure.
- SSH access to both the Proxmox host and the guest VM, since part of this involves running commands inside the VM itself.
- A recent guest OS. For Linux, kernel 5.0 or newer if you're using a VirtIO Block disk (VirtIO SCSI doesn't have this restriction). For Windows, Windows 8/Server 2012 or later, with the VirtIO SCSI driver installed.
Step-by-Step Tutorial
Start with the VM powered off. You can technically add Discard to a running VM's config, but the guest won't see the change until the disk is reattached, which for practical purposes means a reboot anyway.
Enabling Discard through the web interface
- Select your VM in the left-hand tree, then click Hardware.
- Double-click the hard disk you want to modify (usually scsi0 or virtio0).
- Tick the Discard checkbox. If it's greyed out, your storage doesn't support thin provisioning — stop here and check your storage type instead.
- If the guest is Windows, or any OS where you want it to detect the drive as an SSD, also tick SSD emulation. Skip this on VirtIO Block disks — Proxmox doesn't support SSD emulation on that controller type, only on SCSI and SATA.
- Click OK, then start (or restart) the VM.
Enabling Discard from the command line
If you'd rather script this or you're managing a host over SSH, qm set does the same thing. You need the existing disk's storage path, which you can pull from qm config <vmid>:
qm config 101
Look for a line like scsi0: local-lvm:vm-101-disk-0,size=32G. Then reapply it with the discard flag added:
qm set 101 --scsi0 local-lvm:vm-101-disk-0,size=32G,discard=on,ssd=1
Drop ssd=1 if you don't want SSD emulation, or if the disk is on virtio0 instead of a SCSI bus. Restart the VM for the change to take effect.
Turning on TRIM inside the guest
Enabling Discard on the Proxmox side only opens the door — the guest OS still has to actually walk through it. Continuous TRIM (where every delete immediately fires a TRIM command) sounds appealing but tends to hurt performance more than it helps, since it turns every single delete into a blocking storage operation. Scheduled TRIM, run periodically instead of continuously, is what most distributions ship by default and what I'd recommend.
On a Debian or Ubuntu-based guest:
systemctl enable --now fstrim.timer
systemctl status fstrim.timer
This runs fstrim across all mounted filesystems that support it, once a week by default, without you having to think about it again. You can trigger it manually to test that it's actually working:
fstrim -av
A working setup will print something like /: 4.2 GiB (4512731136 bytes) trimmed for each mount point. If it prints nothing or errors out, Discard isn't actually reaching the guest — double check the disk options in Proxmox and confirm you rebooted after changing them.
On Windows, TRIM for SSD-recognized drives runs automatically as part of the scheduled "Optimize Drives" task, which is enabled by default on modern Windows. You can confirm the guest sees the disk as an SSD by opening Optimize Drives from the Start menu search — it should list the media type as Solid State Drive rather than Hard disk drive.
ZFS-backed storage: a separate decision
If your VM disks live on a ZFS pool, there's a second layer worth understanding. ZFS itself can auto-trim free space at the pool level, independent of whether the VM disk has Discard enabled:
zpool set autotrim=on rpool
This tells ZFS to reclaim freed blocks from the underlying physical devices as they become free within the pool. It's separate from guest-level Discard, which reclaims space within the zvol or dataset backing the VM disk. You generally want both, but be aware that ZFS autotrim can add background I/O overhead on busy pools. If you'd rather control when it runs, leave autotrim off and trigger it manually or on a schedule instead:
zpool trim rpool
Commands Explained
| Command | What it does |
|---|---|
qm config <vmid> | Prints the VM's current configuration, including the exact disk string you need before editing it. |
qm set <vmid> --scsi0 ...,discard=on | Rewrites the disk's config line, adding the discard flag so TRIM commands pass through to storage. |
systemctl enable --now fstrim.timer | Enables and immediately starts the systemd timer that runs a filesystem-wide trim on a schedule (weekly by default on Debian and Ubuntu). |
fstrim -av | Manually trims every mounted filesystem that supports it and prints how much space was reclaimed on each one — useful for confirming Discard is actually working. |
zpool set autotrim=on <pool> | Tells ZFS to continuously reclaim freed space at the pool level as blocks become free. |
zpool trim <pool> | Runs a one-time trim pass across the pool's underlying devices instead of leaving it continuous. |
Common Errors
The Discard checkbox being greyed out is the one you'll hit most. It almost always means the storage backing that disk isn't thin-provisioned — a plain LVM volume group without a thin pool is the usual culprit, since regular LVM allocates full-size volumes up front.
Running fstrim -av inside the guest and getting fstrim: /: the discard operation is not supported means Discard isn't actually enabled on the disk, or the VM hasn't been restarted since you enabled it. Config changes to disk options in Proxmox don't apply live to an already-running disk device — the VM needs a full restart, not just a config reload.
If you enabled SSD emulation and it didn't seem to take on a VirtIO Block disk, that's expected, not a bug. Proxmox explicitly does not support SSD emulation on VirtIO Block — only on SCSI and SATA controllers. Switch the disk bus to VirtIO SCSI if you need both discard and SSD emulation together.
Troubleshooting
If space isn't actually being reclaimed on the host after you've confirmed fstrim is running cleanly inside the guest, check the storage type again. On a qcow2-backed directory storage, freed space only shows up as a smaller file on disk if the underlying filesystem supports hole punching (most modern Linux filesystems do) — run ls -lsh against the disk image and compare the apparent size to the actual size to confirm.
On LVM-thin, use lvs on the Proxmox host to check the thin pool's data usage percentage before and after a trim. A drop confirms it's working end to end.
For ZFS, zpool status -t rpool shows whether autotrim is active and gives you basic trim progress if a manual zpool trim is currently running.
If a Windows guest never seems to trim, check that it's using the VirtIO SCSI controller with the latest signed VirtIO drivers installed, not the default SATA emulation. Older VirtIO driver builds had inconsistent UNMAP support, and it's a quick fix — swap the controller type and reinstall drivers from the current virtio-win ISO.
Best Practices
Enable Discard by default on new VMs going forward rather than retrofitting it later — it's one extra checkbox at creation time and saves you from having to schedule downtime just to flip it on afterward.
Stick with scheduled trim (fstrim.timer) over continuous discard for most workloads. Continuous discard sounds more thorough, but issuing a TRIM on every single delete adds latency to write-heavy VMs, especially databases. Weekly scheduled trims recover the vast majority of the benefit with none of that overhead.
Don't enable ZFS pool-level autotrim and expect it to replace guest-level Discard, or the other way around — they operate at different layers and you generally want both if your workload benefits from either.
Honestly, for most homelab setups with a single VM or two doing light work, this whole feature is a nice-to-have rather than something urgent. It matters most when you've got several VMs sharing one SSD and disk space or write amplification is an actual problem you're seeing, not a theoretical one.
Frequently Asked Questions
Does enabling Discard slow down my VM?
Not noticeably in normal use. Scheduled trim runs in short bursts, usually once a week, and the overhead during that window is minimal on modern storage.
Can I enable Discard on a running VM without rebooting?
You can change the config, but the running disk device won't pick up the new flag until the VM is restarted. A config reload isn't enough.
Why is the Discard checkbox greyed out for my disk?
Your storage backend doesn't support thin provisioning. Plain LVM without a thin pool is the most common reason.
Do I need SSD emulation if my host actually has SSDs?
Only if the guest OS needs convincing that the drive is an SSD to schedule its own TRIM maintenance. Modern Linux guests usually don't care either way; some older Windows setups do.
Will this reclaim space that's already been wasted, or only future writes?
Once Discard is on and you run a trim (or wait for the scheduled one), it reclaims currently-free-but-still-allocated blocks immediately, not just going forward.
Conclusion
Discard and TRIM aren't things you'll think about often, but they're cheap to set up and they quietly prevent two real problems: thin-provisioned disks that never shrink back down, and SSDs doing more write work than they need to. Turn on Discard for thin-provisioned disks, add SSD emulation where the guest actually needs it, and let fstrim.timer handle the rest on a schedule instead of leaving it continuous. Ten minutes now saves you a "why is this disk 40 GB larger than it should be" moment six months from now.