← Back to Blog

Running More Than Two macOS VMs on Apple Silicon: the limit, the myths, and what actually works

By Jürgen Koller · 10 min read

Multiple macOS VMs running in parallel on an Apple Silicon Mac

Anyone doing serious virtual-machine work on an Apple Silicon Mac eventually hits an invisible wall: the third macOS VM won't start. Two run in parallel without complaint, but the third aborts with an error. This is not a bug and not a resource problem. It is a deliberately placed limit, and it sits in a place most people don't expect.

This article explains where the limit is really anchored, why the obvious bypass attempts all fail, and which two routes actually work when you need more than two macOS guests at the same time. One for your own machine, one for production use.

What actually happens when the third VM starts

Starting a macOS VM goes through Apple's Virtualization Framework. When you try to start the third concurrently running macOS VM, the framework throws an error with the code VZErrorVirtualMachineLimitExceeded (domain VZErrorDomain, code 6). The plain-text message is simply: "The number of virtual machines exceeds the limit."

The wording matters: this is about concurrently running macOS guests, not the number of VMs you have created. You can keep as many macOS VMs on disk and configured as you like. But only two may boot at the same time. Just as important: the limit only affects macOS guests. Linux guests are not covered by it at all. You can run as many of those in parallel as memory allows.

The key point: the limit lives in the kernel

The intuitive assumption is: if the Virtualization Framework throws the error, then the counting must live in the framework or in the responsible system service virtualizationd — that is, in software you could theoretically bend around. That assumption is wrong, and it is exactly where almost all bypass attempts fail.

Reverse-engineering work (foremost the detailed analysis by Mykola Grymalyuk / khronokernel from 2023) exposed the actual mechanics. The limit is a global integer variable inside the closed-source XNU kernel:

  • hv_apple_isa_vm_quota — the counter, default value 2.
  • hv_trap_vm_create() — the hypercall that claims a slot when a VM starts.
  • hv_vm_destroy_0() — releases the slot again when a VM stops.

Because this counter is a single global kernel variable evaluated inside the hypervisor hypercall itself, the limit applies system-wide per host — not per process and not per user. Two different apps share the same counter; even fast user switching between accounts doesn't help. The VZErrorVirtualMachineLimitExceeded error you see at the app level is only the messenger. The actual refusal happens one layer deeper, in the hypervisor.

The reason for the limit is not technical but a licensing one: Apple's Software License Agreement permits running up to two additional macOS instances in VMs on Apple hardware. The kernel counter is the technical enforcement of exactly that clause. A Mac Studio with plenty of RAM could easily handle more macOS VMs. The boundary is a policy, not a hardware bottleneck.

Why the obvious tricks don't work

Once it's clear that enforcement lives in the kernel, an entire class of ideas collapses. In order:

Patching the framework or virtualizationd

The idea of intercepting the VZError code 6 via code injection, or bending the counting logic in the framework library, misses the actual problem. At best you would suppress the error message — the underlying hypercall hv_trap_vm_create() still returns a failure, and no third VM comes into being, just a swallowed error with no VM behind it. On top of that: any serious VM app runs with Hardened Runtime and library validation, and System Integrity Protection (SIP) forbids injecting into Apple system processes anyway. The same goes for virtualizationd: the service is SIP-protected and doesn't hold the counter itself.

Forging an entitlement

There simply is no entitlement that raises the quota. The real virtualization entitlement only unlocks access to the framework at all, not the count. Inventing an "unlimited" entitlement and re-signing the app fails at notarization and at AMFI (Apple Mobile File Integrity) — unless you disable AMFI, which in turn puts the whole machine into an unsecured state.

QEMU instead of the Virtualization Framework

QEMU uses the lower-level Hypervisor.framework interface and is genuinely unlimited for Linux and Windows guests. For macOS guests it still doesn't help: QEMU's experimental vmapple machine model boots only macOS 12, requires Apple firmware extracted from the Virtualization Framework (legally dubious), and — because the kernel quota sits below both frameworks and is keyed to the macOS guest type — most likely hits the same limit. A modern macOS guest on QEMU is not a practical option today.

Nested virtualization

macOS 15 Sequoia introduced nested virtualization on M3 and later. That sounds tempting — a VM inside a VM, each with its own quota. In practice, though, the feature is meant for Linux guests (a Linux hypervisor inside a Linux VM). macOS-in-macOS is not enabled, and even if it ran, it would not legally raise the two-guest limit.

What actually works — route 1: the kernel route

There is exactly one method that genuinely runs more than two macOS VMs on a single machine: you change the source of the limit itself, the kernel. Because hv_apple_isa_vm_quota is a kernel variable, it can be overridden via a boot argument — however, that very boot argument is gated on release kernels behind an AppleInternal check (CSR_ALLOW_APPLE_INTERNAL, a SIP flag). The documented approach works around this by building and booting a development kernel from Apple's Kernel Debug Kit (KDK), in which this gate doesn't apply.

Before you begin — what this intervention means.

  • It requires SIP permanently disabled and a reduced security level (Permissive Security). The machine is measurably less protected afterwards.
  • The custom kernel is bound to exactly one macOS build and chip. On every macOS update it has to be rebuilt from a new KDK — otherwise the system won't boot cleanly.
  • This cannot be set up from a signed app. It is a manual, per-machine intervention, sensible only on your own hardware and at your own risk.
  • Apple's license permits two additional macOS instances per Apple host. Going beyond that steps outside that clause. For internal development, testing and CI on your own Apple hardware, that is a personal judgment call; commercially renting out the VMs is a separate legal question. Make a backup first.

First, on the running system, you determine the kernel variant matching your build and build a development kernel collection from it. The KDK version and the T-chip variant (e.g. t6020 for M2 Pro/Max) must match the host exactly:

# Determine the host's kernel variant
uname -v | awk -F '/' '{print $NF}' | awk -F '_' '{print $NF}'

# Build the development kernel collection (adjust KDK version + T-variant)
sudo kmutil create \
  --arch arm64e \
  --no-authorization \
  --variant-suffix development \
  --new boot \
  --boot-path VirtualMachine.kc \
  --kernel /Library/Developer/KDKs/KDK_14.0_23A5301h.kdk/System/Library/Kernels/kernel.development.t6020 \
  --repository /Library/Developer/KDKs/KDK_14.0_23A5301h.kdk/System/Library/Extensions \
  --repository /System/Library/Extensions \
  --repository /System/Library/DriverExtensions \
  --explicit-only $(kmutil inspect -V release --no-header | grep -v "SEPHiber" | awk '{print " -b "$1; }')

Then, in the recovery environment, you lower security, set the built collection as the boot kernel, and write the boot argument that raises the quota:

# Run in recoveryOS
csrutil disable
bputil --disable-boot-args-restriction
kmutil configure-boot \
  --volume /Volumes/Macintosh\ HD \
  --custom-boot-object /Volumes/Macintosh\ HD/Users/*/VirtualMachine.kc

# Raise the quota to 255 (maximum is 0x7FFFFFFF)
nvram 40A0DDD2-77F8-4392-B4A3-1E7304206516:boot-args='kcsuffix=development hypervisor=0x1 hv_apple_isa_vm_quota=0xFF'

The three boot arguments mean: kcsuffix=development selects the development kernel variant, hypervisor=0x1 unlocks the extended virtualization features, and hv_apple_isa_vm_quota=0xFF sets the quota to 255. After a reboot, the machine runs with the raised limit. In the original demonstration, nine macOS VMs ran at the same time on an M2 Pro (with the side effect that the fan spun up for the first time).

Before a macOS update, you should revert to the standard kernel, otherwise the update fails:

# In recoveryOS: restore full security
bputil --full-security

The exact commands and current nuances are documented in the original write-up by khronokernel — the authoritative source on this topic. Since Apple changes KDKs and kernels with every release, it's worth comparing against that source before each attempt.

The kicker: Nemeton and other VM apps come along automatically

An often-overlooked point: the limit was never in the VM app. Nemeton, for instance, only calls the standard start method of the Virtualization Framework. Until now that call threw the kernel error on the third VM; on a kernel with a raised hv_apple_isa_vm_quota, the same call simply returns "OK." The app needs no code change at all for this — it starts the third, fourth, fifth VM by itself, because there is no count guard in its code at all. The limit always lay solely in the kernel below it.

What actually limits you then is only the hardware (each macOS VM wants several gigabytes of RAM) and a known side aspect: the counter occasionally leaks. If a guest shuts down uncleanly or crashes, the claimed slot is sometimes not released — then even the next legitimate start fails until you log out and back in or reboot. Good to know when suddenly even the second VM refuses to start.

What actually works — route 2: scale horizontally

The kernel route is powerful, but it only fits your own workbench: SIP off, a rebuild on every update, no rolling it out to others. For productive, maintainable use there is a second route that doesn't fight Apple's enforcement but respects it — and still scales arbitrarily: multiple Macs, two VMs each, controlled from one interface.

Two macOS VMs per physical Apple Silicon host are fully within the license (for development, testing and CI). You add capacity by adding hosts: five Mac minis give ten parallel macOS VMs, ten hosts give twenty. A central control plane handles placement, provisioning, lifecycle, and distribution of VM images across the fleet. This exact pattern has been run in production by specialized Mac cloud providers for years.

The appeal of this route: no lowered security, no custom kernel, no breakage on macOS updates, signed and notarized. It's ordinary distributed-systems work instead of fragile kernel tinkering — and therefore the only route that carries cleanly beyond your own workbench.

Conclusion

The two-VM limit on Apple Silicon is real, it sits in the kernel, and no pure software bypass at the app or framework level can defeat it — suppressing the error just leaves you with no VM at all, let alone a third. If you need more, you have two honest options: the kernel route for your own machine (powerful, but SIP-free and update-fragile) or horizontal scaling across multiple hosts (robust, maintainable, license-clean for dev and test). Which one is right is decided by the use case — not by a trick that outsmarts Apple.

If you want to manage macOS and Linux VMs natively through Apple's Virtualization Framework anyway — with snapshots, a REST API and automation, as a one-time purchase instead of a subscription — Nemeton is the app for it. On a quota-raised kernel it starts more than two VMs without any change; for fleet operation it already ships the building blocks with VM migration between hosts.

View Nemeton in the Store

Frequently Asked Questions

How many macOS VMs can I run at once on Apple Silicon?
Two by default. Apple's Virtualization Framework allows at most two macOS guests running simultaneously per Mac. You can create as many macOS VMs as you like — only the number booted at the same time is capped at two. Linux guests are not affected by this limit.

Why won't my third macOS VM start?
Because the two-VM limit has been reached. The start fails with the error VZErrorVirtualMachineLimitExceeded (VZErrorDomain, code 6): "The number of virtual machines exceeds the limit." This is not a bug and not a resource problem, but a deliberate limit enforced in the macOS kernel.

Does the limit also apply to Linux VMs?
No. The limit applies only to macOS guests. You can run as many Linux VMs in parallel as memory and CPU allow.

Can the two-VM limit be bypassed?
Only in two ways. Pure software tricks at the app or framework level fail because the limit lives in the XNU kernel (the hv_apple_isa_vm_quota variable). What actually works is either a custom development kernel with a raised quota (your own hardware only, with SIP disabled, breaking on every update) or horizontal scaling across multiple Macs running two VMs each.

Does the limit also affect UTM, Parallels or QEMU?
For macOS guests, yes. UTM and Parallels use Apple's Virtualization Framework for macOS VMs and hit the same kernel-level limit. QEMU is unlimited only for Linux and Windows guests; a modern macOS guest on QEMU is currently not a practical option.

Nemeton – VM Manager for macOS

Manage Linux and macOS VMs natively. One-time purchase, no subscription fees.