GPU Passthrough Setup: IOMMU/VFIO in 13 Steps [2026]

Running Windows inside a virtual machine used to mean giving up your GPU’s real performance. Not anymore. GPU passthrough, built on IOMMU and VFIO, hands a physical graphics card directly to a guest VM so it renders games, CUDA workloads, or CAD software at close to bare-metal speed. This tutorial walks through the full 2026 setup on Proxmox VE 9.2, from checking your motherboard’s IOMMU groups to fixing Nvidia’s infamous Code 43 error, tuning CPU pinning, and getting a usable desktop back on your Linux host with Looking Glass. Expect to spend 60 to 120 minutes on a first attempt, longer if your board’s PCIe topology needs extra tuning.

The appeal in 2026 is straightforward. A growing share of Linux desktop users still need Windows occasionally, whether for a specific creative app, a kernel-level anti-cheat game that refuses to run under Proton, or a piece of enterprise software with no Linux build. Reinstalling to dual-boot every time is slow and disruptive. A passthrough VM sidesteps that entirely: the Windows install lives on its own virtual disk, boots in seconds from a saved snapshot, and gets the full, unshared power of the physical GPU the moment it starts. The same technique also underpins a lot of homelab AI work, where isolating a GPU inside its own VM keeps a CUDA toolchain from colliding with whatever else is installed on the bare-metal host.

Google · Preferred Sources

Don't miss new tech stories on Google

Add Tech Insider once in the Google app and our stories appear in your news suggestions.

Add Now

What Is GPU Passthrough and Why It Matters in 2026

GPU passthrough uses the CPU’s built-in I/O Memory Management Unit, or IOMMU, to hand a PCI Express device, usually a graphics card, directly to a virtual machine. Instead of the host operating system sharing the GPU through an emulated or virtualized driver layer, the guest VM gets exclusive, direct access to the physical hardware. Red Hat’s own virtualization documentation puts it plainly: “I/O Memory Management Unit (IOMMU) support on the host machine is necessary to use a GPU on a virtual machine.”

The Gentoo Wiki frames the mechanism from the guest’s point of view: “GPU passthrough is a technology that allows the Linux kernel to directly present an internal PCI GPU as-is for direct use by a virtual machine.” The VM sees the card as if it were plugged directly into it, drivers and all, with no virtualization tax on rendering.

Three use cases drive most 2026 setups. The first is the classic Linux-desktop-plus-Windows-gaming-VM combo, where a player keeps Linux as the daily driver and only spins up Windows for anti-cheat-gated titles or DirectX-only games. The second is AI and machine learning isolation, where a single workstation GPU gets assigned to one VM for CUDA or ROCm development, giving researchers a reproducible, sandboxed environment without touching the host’s driver stack. The third is small-scale cloud gaming or remote workstation hosting, where a homelab or SMB server carves out dedicated GPU VMs for remote users.

Passthrough differs from mediated virtualization technologies like SR-IOV, Nvidia vGPU, or MIG, which split a single physical GPU across multiple guests in software. Full PCIe passthrough assigns the entire card to one VM at a time. It is simpler to configure, works with almost any consumer card, and delivers the closest thing to native performance you’ll get inside a virtual machine.

Prerequisites: Hardware, BIOS, and Software Versions

Before touching a config file, confirm your hardware actually supports passthrough cleanly. Intel VT-d or AMD-Vi (also called AMD-Vi/IOMMU) must be present in the CPU and exposed in the motherboard firmware. A second GPU, or a CPU with integrated graphics, makes life much easier since the host needs its own display output once the discrete card is handed to the VM. Below is the version baseline this tutorial uses, current as of late September 2026.

ComponentVersion Used in This GuideNotes
Host hypervisorProxmox VE 9.2 (9.2-1)Released May 21, 2026, based on Debian 13 “Trixie”
Kernel6.17-based Proxmox kernelDefault since Proxmox VE 9.1; derived from the Ubuntu 25.10 kernel line
QEMU11.0 (Proxmox-packaged)Upstream QEMU reached 11.1.1 in September 2026, but Proxmox ships its own tested build
libvirt12.7.0Released September 1, 2026, for distributions that use libvirt directly instead of Proxmox’s native stack
Guest firmwareOVMF (UEFI)Required for GPU passthrough; legacy SeaBIOS is not reliable for this
Container/LXC runtimeLXC 7.0Bundled with Proxmox VE 9.2 if you also run containers on the same host

On the hardware side, this guide assumes a current-generation GPU such as an Nvidia RTX 5090, RTX 5080, or RTX 5070 Ti, or an AMD Radeon RX 9070 XT or RX 9070 GRE. The steps apply to older cards too. Also confirm your motherboard exposes “Above 4G Decoding,” IOMMU, and SR-IOV toggles in BIOS. Disable CSM/legacy boot, since OVMF requires pure UEFI. If you’re unsure your board plays nicely with passthrough, check its IOMMU group layout first, covered in Step 4 below, before buying anything new.

Step 1: Confirm CPU and Motherboard IOMMU Support

Not every CPU and motherboard pairing groups PCIe devices the same way, and grouping is what makes or breaks a clean passthrough. Broadly, AMD’s X870E chipset tends to isolate devices more cleanly than the mid-range B850, and Intel’s Z890 usually beats the B860 for the same reason: more PCIe lanes routed directly through the CPU rather than shared through the chipset. None of this is a hard guarantee. IOMMU groups depend on the exact board’s PCIe topology, its ACS (Access Control Services) handling, and its firmware, not just the chipset name printed on the box.

PlatformTypical IOMMU Grouping QualityBest For
AMD X870EStrong, usually separates GPU, NVMe, USB, and audio into distinct groupsMulti-device passthrough workstations
AMD B850Good, but grouping varies more by board vendorSingle-GPU passthrough builds on a budget
Intel Z890Capable, but chipset-connected USB/audio/network controllers can complicate groupsSingle-GPU passthrough with a secondary Intel iGPU for the host
Intel B860Adequate for a straightforward single-GPU VMBudget builds with fewer add-in cards

Before buying hardware specifically for passthrough, look up whether other owners of that exact board model have reported clean IOMMU groups for the PCIe slot you plan to use. Community wikis and forum threads for specific board models are more reliable than chipset-level generalizations.

Step 2: Enable IOMMU in BIOS/UEFI

Reboot into your motherboard’s UEFI setup and look for a setting called “IOMMU,” “VT-d” (Intel), or “SVM Mode” plus “AMD-Vi” (AMD). Enable it, along with “Above 4G Decoding” and, on boards that expose it, SR-IOV support even if you don’t plan to use it yet. Disable CSM/Legacy boot mode so the system boots in pure UEFI, since OVMF-based VMs depend on it. Save and reboot.

These menu names vary by vendor. ASUS boards often bury VT-d under Advanced > System Agent Configuration. Gigabyte places SVM Mode under Settings > AMD CBS. MSI usually lists IOMMU directly under Settings > Advanced > AMD Overclocking or Intel Advanced CPU Configuration. If you can’t find the option, search your exact board model plus “enable IOMMU BIOS” before assuming the board doesn’t support it.

Step 3: Enable IOMMU in the Linux Kernel

BIOS-level IOMMU support is only half the job. The Linux kernel needs an explicit boot parameter to activate it. Edit your GRUB configuration and add the platform-appropriate flag.

# For AMD systems, edit /etc/default/grub:
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on iommu=pt"

# For Intel systems:
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt"

# Regenerate the bootloader config, then reboot
update-grub
reboot

The iommu=pt flag puts passthrough-mode translation on host-owned devices, which trims a small amount of translation overhead. It does not change isolation quality. That quality is determined entirely by the IOMMU group layout you’ll check in the next step. After rebooting, confirm the kernel actually initialized IOMMU support:

dmesg | grep -Ei 'IOMMU|DMAR|AMD-Vi'

On an AMD host with the flag correctly applied, expect output resembling this:

[    0.851234] AMD-Vi: IOMMU performance counters supported
[    0.851298] AMD-Vi: Extended features (0x58f77ef22294a5a): PPR NX GT IA PC GA_vAPIC
[    0.851455] AMD-Vi: Interrupt remapping enabled
[    0.852011] AMD-Vi: Virtual APIC enabled
[    1.004221] pci 0000:01:00.0: AMD-Vi: Adding to iommu group 14
[    1.004299] pci 0000:01:00.1: AMD-Vi: Adding to iommu group 14

You should see lines confirming DMAR or AMD-Vi initialization, followed by devices being assigned to numbered IOMMU groups. If the output is empty, double-check the BIOS setting from Step 2 and make sure the GRUB edit actually saved. Typos in /etc/default/grub are the single most common reason this step fails; a missing quote or an extra space is enough to make the whole line silently ignored by the bootloader.

Before moving on, it’s worth understanding roughly which CPUs qualify. On the AMD side, every Ryzen 5000-series, 7000-series, and 9000-series desktop chip supports AMD-Vi, along with Threadripper and EPYC. On the Intel side, VT-d has shipped on mainstream desktop CPUs since the 6th-generation Core lineup, and current 14th-generation and Core Ultra 200-series chips all support it out of the box. The limiting factor in 2026 is almost never the CPU itself. It’s the motherboard firmware’s willingness to expose the toggle and the board’s physical PCIe wiring that determines whether the resulting IOMMU groups are usable.

Step 4: Check IOMMU Groups and Isolate the GPU

As the NixOS passthrough guide from developer Astrid Yu puts it, “Passthrough is based on groups of PCI devices; it’s an all-or-nothing deal.” Every device sharing an IOMMU group with your GPU has to be passed through together, or none of them can be. A quick shell loop lists every group and its member devices.

#!/bin/bash
for iommu_group in $(find /sys/kernel/iommu_groups/ -maxdepth 1 -mindepth 1 -type d | sort -V); do
  echo "IOMMU Group ${iommu_group##*/}:"
  for device in $(ls -1 "$iommu_group/devices/"); do
    echo -e "\t$(lspci -nns "$device")"
  done
done

Look for the group containing your GPU. In an ideal layout, that group holds only the GPU’s graphics function and its HDMI/DisplayPort audio function, nothing else. Here’s what a clean group looks like next to a problematic one.

# Clean group: only the GPU and its audio function, ready to pass through
IOMMU Group 14:
	01:00.0 VGA compatible controller [0300]: NVIDIA Corporation AD102 [GeForce RTX 5090] [10de:2684]
	01:00.1 Audio device [0403]: NVIDIA Corporation AD102 High Definition Audio [10de:22ba]

# Problem group: the GPU shares a group with an unrelated NVMe controller
IOMMU Group 8:
	02:00.0 VGA compatible controller [0300]: Advanced Micro Devices [1002:744c]
	02:00.1 Audio device [0403]: Advanced Micro Devices [1002:ab30]
	03:00.0 Non-Volatile memory controller [0108]: Samsung Electronics NVMe SSD [144d:a80a]

If your GPU also includes your NVMe controller, USB controller, or other add-in cards, you have two options. The first is physically moving the GPU to a different PCIe slot that groups more cleanly, since PCIe topology and physical slot wiring are the real drivers of grouping, not chipset marketing. The second is an ACS override patch, used only as a last resort. ACS override makes the topology look more isolated to software without changing the hardware’s actual peer-to-peer isolation, so treat it as a workaround rather than a fix, and reach for it only after slot-swapping has failed to produce a clean group.

Step 5: Bind the GPU to vfio-pci

Once you’ve confirmed a clean group, the GPU needs to be claimed by the vfio-pci driver instead of the host’s Nvidia or AMD driver, before the host driver has a chance to grab it at boot. First, find the vendor and device IDs with lspci -nnk, then bind them in a modprobe config.

# Find the GPU's PCI IDs (example output: 10de:2684 for GPU, 10de:22ba for HDMI audio)
lspci -nnk | grep -A 3 -i "VGA\|3D controller"

# Create the vfio binding config
cat << EOF > /etc/modprobe.d/vfio.conf
options vfio-pci ids=10de:2684,10de:22ba
softdep nvidia pre: vfio-pci
softdep nouveau pre: vfio-pci
EOF

# Rebuild the initramfs so the binding happens early at boot
update-initramfs -u -k all
reboot

Replace the IDs in the example with the actual vendor:device pairs from your lspci output. Every card ships different values, so copying an example ID from this guide instead of your own hardware’s output is a guaranteed way to bind nothing at all. After rebooting, run lspci -nnk again to confirm the driver switch took effect.

$ lspci -nnk -s 01:00.0
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation AD102 [GeForce RTX 5090] [10de:2684]
	Subsystem: Micro-Star International Co., Ltd. [MSI] Device [1462:5090]
	Kernel driver in use: vfio-pci
	Kernel modules: nouveau, nvidia_drm, nvidia

The “Kernel driver in use” line is what matters. It should read vfio-pci, not nvidia, nouveau, or amdgpu. The “Kernel modules” line simply lists which drivers are available for the device, so seeing nvidia there is normal and expected; it only becomes a problem if it shows up on the “in use” line instead.

Step 6: Install Proxmox VE, QEMU, and libvirt

If you’re building on bare Debian or Ubuntu instead of Proxmox VE, install the virtualization stack directly. Proxmox VE 9.2 bundles QEMU 11.0, libvirt-equivalent tooling, and OVMF already, so this step is mostly relevant for a manual libvirt/KVM setup.

apt update
apt install -y qemu-kvm libvirt-daemon-system libvirt-clients \
  virtinst virt-manager ovmf

systemctl enable --now libvirtd
virsh version

Confirm KVM acceleration is available before continuing:

kvm-ok
# Expected output: "KVM acceleration can be used"

The libvirt 12.7.0 release notes confirm the minimum supported QEMU baseline moved up over the past year, so if you’re pulling libvirt from a rolling-release distribution, verify your installed QEMU version meets the current floor before troubleshooting anything else.

Step 7: Build the Windows VM With OVMF and Attach the GPU

Create the VM using OVMF firmware, the q35 machine type, and host CPU passthrough so the guest sees your actual CPU model rather than a generic virtual one. In Proxmox’s web UI, set BIOS to “OVMF (UEFI),” Machine to “q35,” and CPU type to “host” when creating the VM. If you’re using virt-install directly, the equivalent flags look like this.

virt-install \
  --name win11-gpu-vm \
  --memory 16384 \
  --vcpus 8 \
  --cpu host-passthrough \
  --machine q35 \
  --boot uefi \
  --disk size=120,bus=virtio \
  --cdrom /var/lib/libvirt/images/win11.iso \
  --network network=default,model=virtio \
  --graphics none \
  --hostdev 0000:01:00.0 \
  --hostdev 0000:01:00.1

The two --hostdev flags reference the GPU’s graphics function and its audio function, both needed for a working passthrough. Substitute your actual PCI bus IDs from the lspci output in Step 5. Install Windows normally through the VM’s console, then install the actual GPU driver (Nvidia or AMD) inside the guest once Windows is up, exactly as you would on physical hardware.

Step 8: Fix Nvidia Code 43 With Vendor-ID Spoofing

Nvidia’s Code 43 error, where the guest driver detects it’s running inside a VM and refuses to initialize the card, is far less common with current drivers than it was a few years ago, but it can still appear, particularly with unusual virtual hardware fingerprints. The standard 2026 fix is unchanged: hide the hypervisor signature and spoof a Hyper-V vendor ID in the VM’s libvirt XML.

<features>
  <hyperv mode="custom">
    <vendor_id state="on" value="random12"/>
  </hyperv>
  <kvm>
    <hidden state="on"/>
  </kvm>
</features>

Edit the VM’s XML with virsh edit win11-gpu-vm, add this block inside the <features> section, save, and restart the VM. Test the current Nvidia guest driver before applying this workaround. Modern releases often work without it, and adding the spoof unnecessarily just adds one more moving part to debug later. If Code 43 persists after spoofing the vendor ID, the cause is usually something else entirely: an incomplete device assignment (forgetting the audio function is by far the most frequent culprit), a bad GPU ROM, or a reset problem rather than the hypervisor detection itself. In Proxmox’s VM hardware settings, the equivalent option is a checkbox under the display/PCI device settings labeled “Hide from Guest,” which writes the same XML under the hood.

Step 9: Tune CPU Pinning and Hugepages for Near-Native Speed

A working passthrough VM is only half the goal, the other half is making it fast. Pin virtual CPUs to specific physical cores, isolate those cores from the host scheduler, and back guest memory with hugepages to cut translation overhead.

# Reserve 16GB of 1GB hugepages at boot (add to GRUB_CMDLINE_LINUX_DEFAULT)
default_hugepagesz=1G hugepagesz=1G hugepages=16 isolcpus=4-11

# In the VM's libvirt XML, enable hugepage-backed memory
<memoryBacking>
  <hugepages/>
</memoryBacking>

# Pin vCPUs to isolated physical cores
<cputune>
  <vcpupin vcpu="0" cpuset="4"/>
  <vcpupin vcpu="1" cpuset="5"/>
  <vcpupin vcpu="2" cpuset="6"/>
  <vcpupin vcpu="3" cpuset="7"/>
</cputune>

The isolcpus parameter tells the host scheduler to leave those cores alone so only the VM’s threads run on them, avoiding the stutter that comes from the host and guest fighting over the same physical core. On a system with an 8-core CCD or equivalent, dedicating half the cores to the guest and leaving the rest for the host and its I/O threads is a reasonable starting split. Adjust the exact core numbers to match your CPU’s topology, and check that topology first with lscpu --extended before pinning anything, since guessing wrong on a chiplet-based CPU can pin the VM across two different CCDs and hurt latency more than not pinning at all.

On AMD’s chiplet CPUs specifically, keep every pinned core on the same CCD (Core Complex Die) as the GPU’s attached PCIe lanes where possible. Crossing CCDs adds a round trip over the Infinity Fabric interconnect for every memory access, which shows up as inconsistent frame times even when the average FPS number looks fine. Tools like lstopo from the hwloc package will draw out the CCD and NUMA layout visually if the plain-text lscpu output isn’t clear enough.

Step 10: Set Up Looking Glass for Single-GPU Output

If you only own one GPU, the host loses its display the moment the card gets passed through to the VM. Looking Glass solves this by capturing the Windows guest’s framebuffer through a shared-memory device and streaming it back to a lightweight client on the Linux host, avoiding the latency of RDP, VNC, or SPICE for anything performance-sensitive like gaming.

The setup has four moving parts: an IVSHMEM shared-memory device defined in the VM’s XML, the Looking Glass host application installed inside Windows, the Looking Glass client running on the Linux host, and a dummy HDMI or DisplayPort plug (or a virtual display driver) on the GPU’s output so Windows thinks a monitor is attached. Always check the Looking Glass project’s own release page for the current client and host application versions before installing, since it updates independently of Proxmox, QEMU, and libvirt and this guide won’t guess a version number.

# Add a shared-memory device to the VM XML (sized for up to 1440p @ 144Hz)
<shmem name="looking-glass">
  <model type="ivshmem-plain"/>
  <size unit="M">128</size>
</shmem>

# On the Linux host, launch the client after the VM boots
looking-glass-client -f /dev/shm/looking-glass

Looking Glass does not solve keyboard/mouse focus switching or audio routing by itself, so plan on pairing it with a software KVM tool like Input Leap or a dedicated USB switch if you want to move a single keyboard and mouse between the host and guest sessions.

Step 11: Automate GPU Bind/Unbind and Benchmark Against Bare Metal

If you want to use the same GPU on the host and in a VM at different times, a systemd hook can automatically unbind the card from vfio-pci and rebind it to the host driver when the VM shuts down, then reverse the process when it starts. Proxmox and libvirt both support hook scripts for exactly this.

#!/bin/bash
# /etc/libvirt/hooks/qemu — bind GPU to vfio-pci before VM start, release after

GPU_PCI="0000:01:00.0"
GPU_AUDIO_PCI="0000:01:00.1"
VM_NAME="win11-gpu-vm"

if [ "$2" = "prepare" ] && [ "$1" = "$VM_NAME" ]; then
  systemctl stop display-manager
  virsh nodedev-detach pci_0000_01_00_0
  virsh nodedev-detach pci_0000_01_00_1
elif [ "$2" = "release" ] && [ "$1" = "$VM_NAME" ]; then
  virsh nodedev-reattach pci_0000_01_00_0
  virsh nodedev-reattach pci_0000_01_00_1
  systemctl start display-manager
fi

Once everything is stable, benchmark the VM against the same hardware running bare metal to confirm the overhead is where it should be. Run the same version of 3DMark Steel Nomad or Unigine Heaven on both, with identical driver versions, resolution, and power settings. A realistic side-by-side result on a well-tuned RTX 5090 rig looks something like this.

3DMark Steel Nomad — bare metal (Windows, native install)
Score: 18,940
Average frame rate: 126.3 FPS

3DMark Steel Nomad — passthrough VM (Proxmox host, pinned cores, hugepages)
Score: 18,210
Average frame rate: 121.4 FPS
Delta: -3.9%

A 3-to-4% gap on a GPU-bound synthetic benchmark like this is a good outcome and lines up with what a clean IOMMU group and proper CPU pinning should deliver. If your own numbers show a double-digit gap, work back through Steps 4 and 9 before assuming passthrough itself is the bottleneck. In the overwhelming majority of cases, a large gap traces back to a messy IOMMU group, missing hugepages, or vCPUs pinned across the wrong physical cores rather than any inherent limitation of VFIO.

Workload TypeTypical Overhead vs Bare MetalMain Cause If Higher
GPU-bound rasterized gaming (4K, high settings)0% to 5%Rarely an issue if IOMMU groups are clean
CPU-bound gaming or esports titles2% to 10%Poor CPU pinning, NUMA/CCD locality, scheduler contention
Poorly tuned system (no pinning, no isolcpus)10%+, plus stutterHost and guest threads competing for the same cores

Frame-time consistency matters more than average FPS here. A VM that holds 95% of bare-metal average frame rate but stutters every few seconds is a worse experience than one running 90% with smooth frame pacing, so log 1% lows alongside the average when you compare runs.

The Complete Working Config: All Files in One Place

Here’s every file this tutorial touched, collected in one place so you can copy a known-good starting configuration and adjust the PCI IDs, core numbers, and memory sizes to match your own hardware.

# /etc/default/grub (AMD example)
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on iommu=pt default_hugepagesz=1G hugepagesz=1G hugepages=16 isolcpus=4-11"

# /etc/modprobe.d/vfio.conf
options vfio-pci ids=10de:2684,10de:22ba
softdep nvidia pre: vfio-pci
softdep nouveau pre: vfio-pci

# VM XML additions (inside the <domain> block)
<features>
  <hyperv mode="custom">
    <vendor_id state="on" value="random12"/>
  </hyperv>
  <kvm>
    <hidden state="on"/>
  </kvm>
</features>
<memoryBacking>
  <hugepages/>
</memoryBacking>
<cputune>
  <vcpupin vcpu="0" cpuset="4"/>
  <vcpupin vcpu="1" cpuset="5"/>
  <vcpupin vcpu="2" cpuset="6"/>
  <vcpupin vcpu="3" cpuset="7"/>
</cputune>
<shmem name="looking-glass">
  <model type="ivshmem-plain"/>
  <size unit="M">128</size>
</shmem>

Keep a backup of this config outside the VM itself. If you ever rebuild the host or move to new hardware, having the working GRUB line, modprobe file, and XML block saved separately saves an hour of re-debugging IOMMU groups from scratch.

5 Common GPU Passthrough Pitfalls (and How to Avoid Them)

  • Forgetting the audio function. Every modern GPU exposes an HDMI/DisplayPort audio device as a separate PCI function. Passing through only the graphics function and skipping the audio one is one of the most common reasons a VM boots but has no sound, or worse, throws driver errors.
  • Binding the wrong PCI IDs. Copying vendor:device IDs from a tutorial instead of your own lspci -nnk output guarantees the vfio-pci binding does nothing, since every card model has different IDs. Always pull the IDs from your own hardware.
  • Skipping the IOMMU group check. Jumping straight to binding the GPU without verifying its group is clean leads to confusing failures later, when the VM refuses to start because a device sharing the group is still claimed by the host.
  • Using ACS override as a first resort. ACS override patches can make a bad IOMMU group appear isolated to software, but they don’t change the underlying hardware isolation. Try a different PCIe slot before reaching for this.
  • Assuming a single-GPU setup is plug-and-play. Without a second GPU, integrated graphics, or Looking Glass configured correctly, starting the VM blanks the host’s display with no warning. Test the full unbind/rebind cycle before relying on the system for daily use.

Troubleshooting: 8 GPU Passthrough Errors and Fixes

SymptomLikely CauseFix
VM won’t start, “device in use” errorHost driver still claims the GPUConfirm vfio-pci shows as the kernel driver in lspci -nnk; rebuild initramfs if not
Black screen in guest after bootNo monitor attached to a headless passthrough GPUAdd a dummy HDMI/DisplayPort plug or configure Looking Glass
Code 43 in Windows Device ManagerGuest driver detects hypervisorAdd the Hyper-V vendor-ID spoof from Step 8; verify audio function is also passed through
Empty output from dmesg | grep IOMMUBIOS setting or GRUB flag not appliedRe-check BIOS IOMMU/VT-d toggle; confirm /etc/default/grub edit and rerun update-grub
GPU won’t reset when VM restarts (AMD reset bug)Some AMD cards fail to reset cleanly between VM sessionsReboot the host, or apply a vendor-specific reset workaround if one exists for your card
Stuttering despite high average FPSNo CPU pinning or isolcpus configuredApply the pinning and isolcpus config from Step 9; check for NUMA locality mismatches
VM boots but performance is far below bare metalHugepages not active, or vCPU count mismatched to physical coresConfirm hugepages are allocated with cat /proc/meminfo | grep Huge; reduce vCPU count to match pinned cores
IOMMU group includes unrelated devicesPoor PCIe topology or ACS quirks on that slotMove the GPU to a different physical slot; consult board-specific passthrough reports before using ACS override

Advanced Tips: SR-IOV, Multi-GPU Rigs, and AI/ML Passthrough in 2026

Once a single passthrough VM is stable, a few paths open up. Multi-GPU hosts can dedicate one card to a gaming VM and a second to an AI/ML VM running CUDA or ROCm workloads, with each guest getting exclusive, isolated access to its own hardware, which is useful for reproducible research environments where driver conflicts on a shared host would otherwise be a headache. This pattern shows up often in homelabs built around dual-GPU boards: a smaller card handles the host’s own display and light desktop use, while a flagship card like an RTX 5090 or RX 9070 XT sits dedicated to whichever VM needs it that day, reassigned with a quick shutdown and hostdev swap rather than a full reinstall.

Storage deserves the same attention as the GPU once passthrough is working reliably. A VM pulling textures and game assets off a passed-through NVMe drive, or even a VirtIO-backed disk image sitting on a fast host NVMe pool, avoids the storage bottlenecks that plagued early passthrough setups running games off spinning disks or slow SATA SSDs. If the VM’s disk performance feels the biggest limiting factor after the GPU work is done, that’s usually a sign to move the VM’s virtual disk to its own dedicated NVMe device rather than sharing the host’s boot drive.

SR-IOV (Single Root I/O Virtualization) is worth understanding even if you don’t use it yet. Rather than assigning a whole GPU to one VM, SR-IOV splits certain enterprise and some consumer-adjacent GPUs into multiple virtual functions that several VMs can share simultaneously. It requires firmware and driver support on the specific card, so check the exact model’s SR-IOV compatibility before planning around it. For most homelab and enthusiast builds, full PCIe passthrough remains simpler to set up and troubleshoot than SR-IOV.

For cloud gaming or remote workstation hosting, the display encoder, network path, and input latency usually matter more than the small average-FPS gap between bare metal and a passthrough VM. Pairing a passthrough GPU with a hardware encoder and a low-latency streaming protocol tends to produce a noticeably better remote experience than routing a VM’s display through a generic, high-overhead console protocol. If you’re scaling this to more than a couple of VMs, also look at container-based GPU sharing options like NVIDIA’s device plugin for Kubernetes, which solves a different problem (many lightweight workloads sharing a GPU) than full passthrough (one demanding workload owning a GPU exclusively).

Frequently Asked Questions

Does GPU passthrough hurt gaming performance?

A correctly configured passthrough VM typically loses 0% to 5% of bare-metal FPS in GPU-bound games, and 2% to 10% in CPU-bound titles, depending on how well CPU pinning and hugepages are tuned. Poorly configured systems can lose more than 10% along with visible stutter, so most of the “performance hit” people report is actually a tuning problem, not a fundamental limit of VFIO.

Can I use GPU passthrough with only one GPU?

Yes, this is called single-GPU passthrough. You’ll need either a systemd/libvirt hook script that unbinds the GPU from the host and rebinds it to vfio-pci when the VM starts (and reverses it on shutdown), or a display solution like Looking Glass that keeps the host usable through a shared-memory framebuffer while the VM owns the physical card.

Do I need a workstation GPU, or does a consumer RTX or Radeon card work?

Consumer cards work fine for full PCIe passthrough, which is what this tutorial covers. Workstation or data-center cards become relevant only if you want SR-IOV or vGPU, which split one physical GPU across multiple simultaneous VMs, a different and more restrictive feature than passthrough.

What is Code 43 and why does it happen?

Code 43 is a Windows Device Manager error that appears when Nvidia’s guest driver detects it is running inside a virtual machine and refuses to initialize. Modern Nvidia drivers handle virtualized environments better than older releases, so it’s less common in 2026 than it used to be, but the fix when it does appear is still spoofing the hypervisor’s vendor ID in the VM’s libvirt XML, covered in Step 8.

Can I pass through an AMD GPU instead of an Nvidia one?

Yes, and the setup steps (BIOS IOMMU, GRUB flags, vfio-pci binding, VM creation) are identical. AMD cards generally don’t need the Code 43 vendor-ID workaround since that issue is Nvidia-specific, but some AMD GPUs are affected by a known “reset bug” where the card fails to reset cleanly when a VM restarts, requiring a full host reboot or a card-specific workaround.

What’s the difference between GPU passthrough and vGPU/SR-IOV?

Passthrough assigns an entire physical GPU to one VM at a time, exclusively. SR-IOV and Nvidia vGPU split a single physical GPU into multiple virtual functions that several VMs or containers can use simultaneously, which requires specific firmware and driver support on the card. Passthrough is simpler to set up and delivers closer-to-native performance for one demanding VM. SR-IOV and vGPU trade some performance and setup complexity for the ability to share one GPU across many lighter workloads instead.

Do I need Proxmox specifically, or does this work on plain Debian or Ubuntu?

Proxmox VE is a convenience layer over QEMU, KVM, and libvirt-equivalent tooling, not a requirement. Every step in this guide, from enabling IOMMU to binding vfio-pci to writing the VM’s XML, works the same way on plain Debian, Ubuntu, or any distribution running a recent kernel with libvirt and QEMU installed manually, as shown in Step 6.

Is GPU passthrough legal, or does it violate driver license terms?

Running consumer Nvidia or AMD drivers inside a single VM on hardware you own, for personal use, is standard practice within the open-source virtualization community documented by projects like Proxmox, libvirt, and the Gentoo Wiki. Licensing restrictions around GPU virtualization are aimed primarily at data-center-scale, multi-tenant deployment scenarios rather than a single enthusiast running one VM on their own desktop, but always check the current driver EULA for your specific card and use case if you’re deploying at any commercial scale.

Related Coverage

Sofia Lindström

Sofia Lindström

Editor-in-Chief

Sofia Lindström is the Editor-in-Chief at Tech Insider, where she leads editorial strategy and oversees coverage across AI, cybersecurity, and enterprise technology. With over a decade in Swedish tech journalism, she previously served as technology editor at Dagens Industri and covered the Nordic startup ecosystem for Breakit. Sofia holds an MSc in Media Technology from KTH Royal Institute of Technology and is a frequent speaker at Web Summit and Slush. She is passionate about making complex technology accessible to business leaders.

View all articles