Multipass turned a cached Ubuntu image into a running VM in 59 seconds on our test box. You get a real Ubuntu kernel from one command, with no hypervisor to configure.
Below, you install Multipass on Linux and macOS, then take a Multipass Ubuntu instance through launch, exec, file sharing, cloud-init, snapshots and cleanup. Every timing comes from a lab run, and so does one exec bug in the current stable release that can hang your scripts.
Tested October 2026 on Multipass 1.16.4 (Ubuntu 26.04 and 24.04).
Prerequisites
To run Multipass, you need hardware virtualization, spare RAM and a few GiB of disk.
- Ubuntu 26.04 or 24.04. Canonical ships the same snap for other distributions that run snapd, but we tested Ubuntu only.
- A CPU with Intel VT-x or AMD-V visible to the operating system.
- About 1 GiB of host RAM for each running instance at default size.
- About 1.1 GiB of disk per instance, plus up to 0.8 GiB per cached image.
- A user with sudo rights.
Our hosts were two OpenStack VMs with nested KVM. The Ubuntu 26.04 host had 2 vCPUs and 8 GB of RAM. The Ubuntu 24.04 host had 2 vCPUs and 4 GB.
Following every step keeps up to five instances running at once, so give the host about 8 GB of RAM. On a 4 GB host, keep at most two instances running, which is what our 4 GB host ran. Stop any instance the current step does not use with multipass stop, and purge primary with multipass delete --purge primary right after its mount check in Step 5.
Step 1: Confirm KVM Is Available
On Linux, Multipass runs every instance on QEMU with KVM, so /dev/kvm must exist.
To confirm KVM, check the device node and the CPU flags:
ls -l /dev/kvm
grep -cE 'vmx|svm' /proc/cpuinfo
A device node and any count above zero mean KVM is usable:
crw-rw---- 1 root kvm 10, 232 Oct 13 23:48 /dev/kvm
4
When Multipass runs inside a VM, the hypervisor has to pass VT-x or AMD-V through. If /dev/kvm is missing there, enable nested virtualization on the host first. ARM64 CPUs have no vmx or svm flag, so on an ARM host the device node is the only check.
Step 2: Install Multipass
Canonical ships Multipass as a snap on Linux and as a signed installer on macOS.
Install on Linux
Install the snap from the stable channel:
sudo snap install multipass
The snap was installed in 55.6 seconds on the 26.04 host and 57.9 seconds on 24.04:
multipass 1.16.4 from Canonical** installed
Once the snap is in place, confirm that the client and the daemon report the same version:
multipass version
Both halves answered on both hosts:
multipass 1.16.4
multipassd 1.16.4
Later upgrades are handled by snapd automatically.
On Debian, Fedora or Rocky Linux, set up snapd first with our guides for snapd on Debian, Fedora and Rocky Linux. The same snap install command follows. Canonical notes that your user must belong to the group that owns the Multipass socket, which can be wheel or admin rather than sudo there.
Error: “failed to open file ‘/var/snap/multipass/common/data/multipassd/multipass_root_cert.pem'”
Our first multipass version, run the moment the snap finished, failed like this:
[error] [client] Caught an unhandled exception: failed to open file '/var/snap/multipass/common/data/multipassd/multipass_root_cert.pem': No such file or directory(2)
Multipass had not written the daemon certificate yet. If you see this, wait a few seconds and rerun the command.
In a provisioning script, poll for the daemon line. multipass version exits 0 even when the daemon is down and prints only the client line, so the exit code alone proves nothing:
until multipass version 2>/dev/null | grep -q '^multipassd'; do sleep 1; done
With the daemon stopped, this loop kept waiting. It returned 3 seconds after the daemon came back.
Install on macOS
On a Mac, download the .pkg from the Multipass install page and run it. If you use Homebrew, install the same package as a cask:
brew install --cask multipass
Canonical lists macOS 14 Sonoma or newer and an admin account as requirements. The Mac installer was not tested for this guide. You use the same CLI on both platforms, and every number below comes from the Linux hosts.
Step 3: Launch a Multipass Ubuntu VM
One command downloads the current LTS image and boots it. First, see what you can launch:
multipass find
The catalogue on our 26.04 host:
Image Aliases Version Description
core core16 20200818 Ubuntu Core 16
core18 20211124 Ubuntu Core 18
core20 20230119 Ubuntu Core 20
core22 20230717 Ubuntu Core 22
core24 20240603 Ubuntu Core 24
core26 20260506 Ubuntu Core 26
22.04 jammy 20261004 Ubuntu 22.04 LTS
24.04 noble 20260926 Ubuntu 24.04 LTS
26.04 resolute,lts 20260927 Ubuntu 26.04 LTS
daily:26.10 stonking,devel 20261006 Ubuntu 26.10
appliance:adguard-home 20200812 Ubuntu AdGuard Home Appliance
appliance:mosquitto 20200812 Ubuntu Mosquitto Appliance
appliance:nextcloud 20200812 Ubuntu Nextcloud Appliance
appliance:openhab 20200812 Ubuntu openHAB Home Appliance
appliance:plexmediaserver 20200812 Ubuntu Plex Media Server Appliance
Blueprint (deprecated) Aliases Version Description
anbox-cloud-appliance latest Anbox Cloud Appliance
charm-dev latest A development and testing environment for charmers
docker 0.4 A Docker environment with Portainer and related tools
jellyfin latest Jellyfin is a Free Software Media System that puts you in control of managing and streaming your media.
minikube latest minikube is local Kubernetes
ros2-humble 0.1 A development and testing environment for ROS 2 Humble.
ros2-jazzy 0.1 A development and testing environment for ROS 2 Jazzy.
26.04 carries the lts alias, so it is picked when you launch without an image name. Blueprints are marked deprecated, so you should build on plain images and cloud-init instead.
Launch an instance named web01:
multipass launch --name web01
Our first launch took 73.2 seconds, image download included.
List your instances:
multipass list
web01 is running with a private address:
Name State IPv4 Image
web01 Running 10.248.91.158 Ubuntu 26.04 LTS
To see the resources it got, ask for its details:
multipass info web01
Defaults are 1 CPU, 1 GiB of RAM and a 5 GiB disk:
Name: web01
State: Running
Snapshots: 0
IPv4: 10.248.91.158
Release: Ubuntu 26.04.1 LTS
Image hash: 8800651811af (Ubuntu 26.04 LTS)
CPU(s): 1
Load: 1.33 0.40 0.14
Disk usage: 2.2GiB out of 4.8GiB
Memory usage: 352.7MiB out of 950.7MiB
Mounts: --
The version check, launch, list and info as one terminal session on the 26.04 host:

On Linux, every instance sits on mpqemubr0, a NAT bridge served by its own dnsmasq. Its subnet was 10.248.91.0/24 on the 26.04 box and 10.122.3.0/24 on the 24.04 box, so expect a different one on yours. You can reach instances from the host, which the curl test in Step 7 relies on.
multipass networks lists the host interfaces you can bridge with --network or --bridged. On Linux, Multipass needs NetworkManager to create that bridge, and Ubuntu Server ships without it, so there you build the bridge with Netplan first. We did not bridge on these cloud hosts.
Launch a second instance now. Later steps use db01 for the native mount and the suspend test:
multipass launch --name db01
Once the image was cached, db01 took 58.7 seconds, so most of the wait is boot and cloud-init rather than the download.
Step 4: Choose Release and Size
To pick a release and size, pass both at launch time. Here, app01 gets Ubuntu 24.04 with 2 CPUs, 2 GiB of RAM and a 15 GiB disk:
multipass launch 24.04 --name app01 --cpus 2 --memory 2G --disk 15G
Launching app01 took 63.2 seconds, including the 24.04 image download. Confirm the sizing:
multipass info app01
All three values reached the guest:
Name: app01
State: Running
Snapshots: 0
IPv4: 10.248.91.165
Release: Ubuntu 24.04.5 LTS
Image hash: 6a81c37564db (Ubuntu 24.04 LTS)
CPU(s): 2
Load: 1.70 0.48 0.16
Disk usage: 1.9GiB out of 14.4GiB
Memory usage: 384.8MiB out of 1.9GiB
Mounts: --
If you plan real workloads, give them more than the default disk. A fresh default instance already used 2.2 GiB of its 4.8 GiB.
Step 5: Run Commands
exec runs one command and returns. shell gives you an interactive login.
Run a single command inside web01:
multipass exec web01 -- lsb_release -ds
You get the release string back:
Ubuntu 26.04.1 LTS
Commands run as the ubuntu user in its home directory:
multipass exec web01 -- bash -c "whoami; pwd; nproc"
User, directory and CPU count:
ubuntu
/home/ubuntu
1
To work interactively, open a login shell:
multipass shell web01
You land on the standard Ubuntu login banner and prompt. Type exit to return to the host:
Welcome to Ubuntu 26.04.1 LTS (GNU/Linux 7.0.0-34-generic x86_64)
* Documentation: https://docs.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Wed Oct 14 00:11:49 UTC 2026
System load: 0.19 Processes: 119
Usage of /: 65.6% of 3.70GB Users logged in: 0
Memory usage: 25% IPv4 address for ens3: 10.248.91.158
Swap usage: 0%
Expanded Security Maintenance for Applications is not enabled.
35 updates can be applied immediately.
30 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
ubuntu@web01:~$
If you run multipass shell with no name, Multipass launches one more 1 GiB instance called primary and mounts your home directory into it:
multipass shell
Exit that shell, then check the mount from the host:
multipass info primary | grep -A1 Mounts
Our home directory appeared as ~/Home inside the guest:
Mounts: /home/klinsmann => Home
UID map: 1000:default
exec loops on exit status 4
On 1.16.4, a remote exit status of 4 makes the client run the command again, with no end. To count the runs in 15 seconds, use this one-liner:
timeout 15 multipass exec web01 -- sh -c "echo run; exit 4" | grep -c run
We got 93 runs on the 26.04 host and 89 to 91 on the 24.04 host:
93
Exit statuses 1, 3 and 5 ran once each. Because systemctl is-active returns 4 for a unit that does not exist, a health check against a missing service hangs forever. We hit it after purging nginx, when a status check never came back.
Multipass reserves return code 4 for a Retry signal inside the client, and the remote status collides with it. Upstream tracked this as issue #3771, and PR #4567 fixed it in the 1.17 line. Neither 1.16.4 nor the 1.16.5 release candidate includes the fix. On the 1.17 release candidate from the beta channel, the same test ran once and the client returned 4.
Until you run 1.17, keep the remote status away from 4. This health check remaps 4 to 104 and passes every other code through:
multipass exec web01 -- sh -c 'systemctl is-active nginx; rc=$?; [ "$rc" -eq 4 ] && rc=104; exit "$rc"'
The state prints once and the client exits 104, so a failing check still fails:
inactive
When you only want the text and not the status, append || true instead. The client then exits 0:
multipass exec web01 -- sh -c "systemctl is-active nginx || true"
Same output, exit 0:
inactive
On the 24.04 host, the loop and the workaround side by side:

Error: “unsupported machine type” after leaving the beta
This only applies if you moved to the beta channel with sudo snap refresh multipass --beta and then went back to 1.16.4 with sudo snap revert multipass. When snapd stops the daemon for the switch, Multipass suspends running instances. The 1.17 QEMU saves that state with machine type pc-i440fx-10.0, which the 1.16.4 QEMU cannot load.
multipass list still showed both of our instances as Running, but every exec failed:
exec failed: ssh connection failed: 'No route to host'
The real cause only appears in the daemon journal:
sudo journalctl -u snap.multipass.multipassd -o cat | grep "unsupported machine type"
Each daemon start logs one line per instance. Ours shows four because neither multipass restart nor sudo snap restart multipass cleared it:
qemu-system-x86_64: unsupported machine type
qemu-system-x86_64: unsupported machine type
qemu-system-x86_64: unsupported machine type
qemu-system-x86_64: unsupported machine type
A forced stop deletes the suspend image, so the next start is a cold boot. Canonical warns that --force can corrupt a running instance, so use it only on instances in this state, and repeat it for each one:
multipass stop --force web01
multipass start web01
snap revert keeps tracking the beta channel, so a later refresh would pull the beta again. Switch back to stable:
sudo snap switch --channel=latest/stable multipass
snap info multipass then reports tracking: latest/stable.
Step 6: Share Files
transfer copies files once. mount shares a host directory live.
Create a directory to share. Our test file was 256 MiB of random data:
mkdir -p ~/shared
dd if=/dev/urandom of=~/shared/blob.bin bs=1M count=256 status=none
Copy it into the instance:
multipass transfer ~/shared/blob.bin web01:/home/ubuntu/
Copying took 2.66 seconds. To check that it arrived, list it inside the guest:
multipass exec web01 -- ls -lh /home/ubuntu/blob.bin
All 256 MiB, owned by the ubuntu user:
-rw-rw-r-- 1 ubuntu ubuntu 256M Oct 13 23:54 /home/ubuntu/blob.bin
Classic mount over SSHFS
Classic is the default mount type. Mount the directory into web01:
multipass mount ~/shared web01:/home/ubuntu/shared
Our first mount took 18.8 seconds, because the multipass-sshfs snap was installed inside the guest during that time. Verify the filesystem type:
multipass exec web01 -- findmnt -no SOURCE,FSTYPE /home/ubuntu/shared
Classic mounts are SSHFS under FUSE:
:/home/klinsmann/shared fuse.sshfs
Native mount over 9p
Native mounts use file sharing built into the hypervisor. They can only be attached to a stopped instance. Against a running one, Multipass refuses:
mount failed: Please stop the instance db01 before attempting native mounts.
Stop the instance, add the mount, then start it again:
multipass stop db01
multipass mount --type native ~/shared db01:/home/ubuntu/shared
multipass start db01
Inside the guest it shows up as 9p over virtio:
multipass exec db01 -- findmnt -no SOURCE,FSTYPE,OPTIONS /home/ubuntu/shared
Note the 512,000-byte msize:
m9108290a489134bea4b8606eb1a674 9p rw,relatime,access=client,msize=512000,trans=virtio
Mount speed compared
Both types were measured from 1-CPU instances on the 26.04 host. Each run wrote 256 MiB with dd and conv=fsync, then read the 256 MiB test file back after dropping caches on host and guest.
| Mount type | Write, 3 runs | Read, 3 runs | Create 2,000 x 4 KiB files | List and delete |
|---|---|---|---|---|
| Classic (SSHFS) | 85, 83, 81 MB/s | 99, 101, 100 MB/s | 12.6 s | 3.2 s |
| Native (9p) | 24, 26, 24 MB/s | 29, 30, 29 MB/s | 12.1 s | 6.4 s |
| Guest local disk | not measured | not measured | 7.1 s | not measured |
On these nested KVM hosts, classic was about 3.4 times faster than native for large files. Native only matched it on small-file creates, and deletes took twice as long. Measure both on your own hardware before you switch types.
To remove a single mount, name its target:
multipass umount web01:/home/ubuntu/shared
multipass umount db01 removes every mount on db01 in one go.
Step 7: Provision with cloud-init
A cloud-init file turns a launch into a configured server. Create one in your home directory:
vim ~/web-init.yaml
Add packages, a web page and a command to run on first boot:
#cloud-config
package_update: true
packages:
- nginx
- htop
write_files:
- path: /var/www/html/index.html
content: |
<h1>web02 provisioned by cloud-init</h1>
runcmd:
- systemctl enable --now nginx
Launch an instance with it:
multipass launch --name web02 --cloud-init ~/web-init.yaml
With nginx in the package list, the launch took 64.8 seconds. Confirm cloud-init finished:
multipass exec web02 -- cloud-init status
A clean run reports done:
status: done
To fetch the page from the host, pull the IPv4 address from the third CSV field of multipass info:
curl -s http://$(multipass info web02 --format csv | tail -1 | cut -d, -f3)/
nginx serves the file cloud-init wrote:
<h1>web02 provisioned by cloud-init</h1>
You can reuse the same user-data for VMs created with virt-install on plain KVM.
Step 8: Suspend, Resize and Snapshot
Suspend is the fast path. A resume took 2.3 seconds, while a cold start took 26.8 seconds.
Suspend db01, then bring it back. If you stopped db01 earlier on a 4 GB host, start it first, because suspend does nothing to a stopped instance:
multipass suspend db01
multipass start db01
Each step took 2.3 seconds. While suspended, multipass list shows no address:
db01 Suspended -- Ubuntu 26.04 LTS
Snapshot before you change it
We ran the snapshot, resize and restore sequence on the 24.04 host, in this order. The outputs come from that run, apart from the snapshot error and timing from the 26.04 host.
Snapshots need a stopped instance. On a running one you get this:
snapshot failed: Multipass can only take snapshots of stopped instances.
Stop web02 and take a named snapshot:
multipass stop web02
multipass snapshot web02 --name before-upgrade --comment "clean nginx box"
The snapshot was written in 0.33 seconds:
Snapshot taken: web02.before-upgrade
List snapshots across all instances:
multipass list --snapshots
One snapshot, with its comment:
Instance Snapshot Parent Comment
web02 before-upgrade -- clean nginx box
Resize the stopped instance
While web02 is still stopped, change CPUs, memory and disk with multipass set:
multipass set local.web02.cpus=2
multipass set local.web02.memory=2G
multipass set local.web02.disk=10G
Read each value back. On 1.16.4, multipass get takes one key per call, and three keys in one call fail with Need at most one setting key.
multipass get local.web02.cpus
multipass get local.web02.memory
multipass get local.web02.disk
All three changed:
2
2.0GiB
10.0GiB
Disks only grow. An attempt to go from 10 GiB to 8 GiB failed:
set failed: Invalid setting 'local.web02.disk=8G': Disk can only be expanded
Start web02 and check the new size:
multipass start web02
multipass info web02 | grep -E "Snapshots|CPU|Disk usage|Memory"
The guest now has 2 CPUs, 2 GiB and a 10 GiB disk:
Snapshots: 1
CPU(s): 2
Disk usage: 2.2GiB out of 9.6GiB
Memory usage: 394.0MiB out of 1.9GiB
Restore the snapshot
To test a restore, purge nginx from web02:
multipass exec web02 -- sudo apt-get -qq -y purge nginx nginx-common
Then run the health check from Step 5 against web02, in its exit-4-safe form:
multipass exec web02 -- sh -c 'systemctl is-active nginx; rc=$?; [ "$rc" -eq 4 ] && rc=104; exit "$rc"'
nginx is gone, and the client exits 104:
inactive
Stop web02 and roll it back:
multipass stop web02
multipass restore web02.before-upgrade --destructive
--destructive discards the current state of the instance. The restore confirms:
Snapshot restored: web02.before-upgrade
Start web02 and rerun the same health check:
multipass start web02
multipass exec web02 -- sh -c 'systemctl is-active nginx; rc=$?; [ "$rc" -eq 4 ] && rc=104; exit "$rc"'
nginx is back, and the check exits 0:
active
The sizing went back too. Check it the same way as after the resize:
multipass info web02 | grep -E "Snapshots|CPU|Disk usage|Memory"
1 CPU, 1 GiB and a 5 GiB disk, the values from snapshot time:
Snapshots: 1
CPU(s): 1
Disk usage: 2.2GiB out of 4.8GiB
Memory usage: 377.5MiB out of 950.7MiB
If you resize an instance, take a fresh snapshot afterwards, or a restore quietly undoes the change.
Step 9: Delete, Recover and Purge
delete is reversible until you purge. Delete app01:
multipass delete app01
multipass list keeps it, marked Deleted. Your other rows depend on which instances you kept or stopped. Ours was captured before the primary instance existed:
Name State IPv4 Image
app01 Deleted -- Ubuntu 24.04 LTS
db01 Running 10.248.91.209 Ubuntu 26.04 LTS
web01 Running 10.248.91.158 Ubuntu 26.04 LTS
web02 Running 10.248.91.191 Ubuntu 26.04 LTS
Bring it back with multipass recover app01, then start it. To remove an instance for good, purge it:
multipass delete --purge app01
Purging app01 shrank the instance directory from 5.3 GiB to 4.3 GiB. To clear the whole lab, stop and purge everything:
multipass stop --all
multipass delete --all --purge
Stopping four instances took 16.3 seconds. The purge took 0.37 seconds, and multipass list printed No instances found.
A purge leaves the image cache alone, and ours still held 1.4 GiB for the 26.04 and 24.04 images. To remove Multipass and its data completely, run:
sudo snap remove --purge multipass
snapd confirms, and /var/snap/multipass is gone:
multipass removed
On macOS, Canonical documents an uninstall script instead. It asks whether to delete your VMs and daemon data as well. If you installed with Homebrew, run the script before brew uninstall --cask multipass, because the cask uninstall deletes the script and leaves the daemon data under /var/root/Library.
sudo sh "/Library/Application Support/com.canonical.multipass/uninstall.sh"
Measured Footprint per Instance
A default instance cost about 1 GiB of host RAM and 1.1 GiB of disk on the 26.04 host.
| Measurement | Ubuntu 26.04 host | Ubuntu 24.04 host |
|---|---|---|
| snap install | 55.6 s | 57.9 s |
| First launch, image download included | 73.2 s | 75.9 s |
| Launch from cached image | 58.7 s | not measured |
| Launch with cloud-init and nginx | 64.8 s | not measured |
| Cold start / suspend / resume | 26.8 s / 2.3 s / 2.3 s | not measured |
| Host RAM (QEMU RSS), default instance after boot | 1,069 to 1,070 MiB | not measured |
| Disk per default instance | 1.09 GiB qcow2, 5 GiB virtual | not measured |
| Cached image | 826 MiB (26.04), 597 MiB (24.04) | not measured |
| transfer, 256 MiB | 2.66 s | not measured |
| exec status 4 loop, runs in 15 s | 93 | 89 to 91 |
Host RAM is the number to watch. web01 reported 352.7 MiB in use inside the guest, while its QEMU process held 1,070 MiB. Four instances held 3,753 MiB together and left 3,577 MiB available on the 8 GB host.
Every instance is a full qcow2 copy of the image, with no backing file. Disk grows by 0.8 to 1.1 GiB per launch, however many instances share a release.
When you need libvirt storage pools or guests bridged onto your LAN, move up to KVM and QEMU on Ubuntu 26.04. For multi-machine labs driven from a file, Vagrant is the closer fit.