If you manage KVM virtual machines in production, virsh is the tool you will reach for more than anything else. It is the primary command-line interface for libvirt and gives you full control over every aspect of a guest VM, from creation to migration to teardown. This reference covers every virsh operation I use regularly after 10+ years of running KVM hosts in production environments, organized by task category with real command examples and expected output.
All commands below assume you are running as root or using a user with proper libvirt group membership. The default connection URI is qemu:///system. If you need to connect to a remote host, append -c qemu+ssh://root@remotehost/system to any virsh command.
Prerequisites
You need a working KVM hypervisor with libvirt installed and the libvirtd service running. If you have not set this up yet, follow our guide on how to install KVM virtualization on Linux. Verify your environment is ready:
$ virsh version
Compiled against library: libvirt 9.0.0
Using library: libvirt 9.0.0
Using API: QEMU 9.0.0
Running hypervisor: QEMU 7.2.0
1. VM Lifecycle Management
These are the bread and butter commands for controlling the state of your virtual machines. You will use these dozens of times a day on a busy hypervisor.
Define a VM from XML
Defining a VM registers it with libvirt without starting it. This is how you import a VM configuration or create one from a prepared XML file.
$ virsh define /etc/libvirt/qemu/webserver01.xml
Domain 'webserver01' defined from /etc/libvirt/qemu/webserver01.xml
Start, Shutdown, Reboot, and Force Stop
Starting a VM boots it from a powered-off state. Shutdown sends an ACPI signal to the guest OS for a clean poweroff. Reboot does the same but brings the guest back up. If a guest is unresponsive and will not shut down cleanly, destroy pulls the plug immediately, similar to yanking the power cord on a physical server.
$ virsh start webserver01
Domain 'webserver01' started
$ virsh shutdown webserver01
Domain 'webserver01' is being shut down
$ virsh reboot webserver01
Domain 'webserver01' is being rebooted
$ virsh destroy webserver01
Domain 'webserver01' destroyed
A common mistake is using destroy when you mean shutdown. The name is misleading. Destroy does not delete the VM or its disks. It is the equivalent of a hard power-off. The VM definition and storage remain intact.
Suspend and Resume
Suspend pauses the VM and frees its CPU cycles while keeping it in memory. Resume brings it back instantly. This is useful during host maintenance windows when you need to briefly pause workloads without a full reboot cycle.
$ virsh suspend webserver01
Domain 'webserver01' suspended
$ virsh resume webserver01
Domain 'webserver01' resumed
Undefine (Remove) a VM
Undefine removes the VM definition from libvirt. The VM must be shut down first. Add --remove-all-storage to also delete the associated disk images. Without that flag, the disk files remain on the filesystem.
$ virsh undefine webserver01
Domain 'webserver01' has been undefined
$ virsh undefine webserver01 --remove-all-storage --nvram
Domain 'webserver01' has been undefined
Volumes removed: /var/lib/libvirt/images/webserver01.qcow2
2. VM Information and Status
Before making changes to any VM, always check its current state. These commands give you the full picture of what is running and how it is configured.
List VMs
The most frequently used virsh command. Without flags, it only shows running VMs. Always use --all to include stopped guests.
$ virsh list --all
Id Name State
---------------------------------
1 webserver01 running
3 dbserver01 running
- testvm02 shut off
- staging-app shut off
Detailed VM Information
Use dominfo to get a quick summary of a VM’s resource allocation and state. For block devices and network interfaces, use domblklist and domiflist.
$ virsh dominfo webserver01
Id: 1
Name: webserver01
UUID: a3f2b8c1-4d5e-6f7a-8b9c-0d1e2f3a4b5c
OS Type: hvm
State: running
CPU(s): 4
CPU time: 1245.3s
Max memory: 8388608 KiB
Used memory: 8388608 KiB
Persistent: yes
Autostart: enable
Managed save: no
Security model: apparmor
Security DOI: 0
$ virsh domblklist webserver01
Target Source
---------------------------------------------------
vda /var/lib/libvirt/images/webserver01.qcow2
sda /var/lib/libvirt/images/data01.qcow2
To see which network interfaces are attached:
$ virsh domiflist webserver01
Interface Type Source Model MAC
--------------------------------------------------------------
vnet0 bridge br0 virtio 52:54:00:a1:b2:c3
vnet1 network default virtio 52:54:00:d4:e5:f6
Performance Stats and Full XML Dump
For performance troubleshooting, domstats provides CPU, memory, block I/O, and network counters in one shot. To export the complete VM configuration, use dumpxml.
$ virsh domstats webserver01 --cpu-total --block --interface
Domain: 'webserver01'
cpu.time=124530000000
cpu.user=98200000000
cpu.system=26330000000
block.count=1
block.0.name=vda
block.0.rd.reqs=45230
block.0.rd.bytes=1845006336
block.0.wr.reqs=12840
block.0.wr.bytes=524288000
net.count=1
net.0.name=vnet0
net.0.rx.bytes=2048576000
net.0.tx.bytes=1024288000
$ virsh dumpxml webserver01 > /tmp/webserver01-backup.xml
I always dump the XML before making any changes. It takes two seconds and has saved me from bad edits more times than I can count.
3. Storage Management
Virsh handles storage through pools and volumes. A pool is a directory, LVM volume group, NFS mount, or other storage backend. Volumes are the individual disk images within a pool.
Storage Pools
$ virsh pool-list --all
Name State Autostart
---------------------------------
default active yes
images active yes
backups active no
$ virsh pool-info default
Name: default
UUID: b1c2d3e4-f5a6-7b8c-9d0e-1f2a3b4c5d6e
State: running
Persistent: yes
Autostart: yes
Capacity: 500.00 GiB
Allocation: 312.45 GiB
Available: 187.55 GiB
Volume Operations
List existing volumes in a pool, create new ones, or remove volumes you no longer need.
$ virsh vol-list default
Name Path
---------------------------------------------------------------
webserver01.qcow2 /var/lib/libvirt/images/webserver01.qcow2
dbserver01.qcow2 /var/lib/libvirt/images/dbserver01.qcow2
$ virsh vol-create-as default newdisk01.qcow2 50G --format qcow2
Vol newdisk01.qcow2 created
$ virsh vol-delete newdisk01.qcow2 --pool default
Vol newdisk01.qcow2 deleted
Hot-Attach a Disk to a Running VM
You can attach additional disks without downtime. The --persistent flag ensures the disk survives a reboot. Without it, the disk attachment is lost when the VM shuts down.
$ virsh attach-disk webserver01 /var/lib/libvirt/images/data02.qcow2 vdb \
--driver qemu --subdriver qcow2 --persistent
Disk attached successfully
$ virsh detach-disk webserver01 vdb --persistent
Disk detached successfully
4. Networking
KVM networking through libvirt supports NAT, bridged, macvtap, and isolated networks. For production servers, bridged networking is standard, but the default NAT network works fine for lab and development environments.
Network Listing and Details
$ virsh net-list --all
Name State Autostart Persistent
----------------------------------------------
default active yes yes
isolated active no yes
br-prod active yes yes
$ virsh net-info default
Name: default
UUID: c3d4e5f6-a7b8-9c0d-1e2f-3a4b5c6d7e8f
Active: yes
Persistent: yes
Autostart: yes
Bridge: virbr0
Get Guest IP Addresses
This is one of the most useful commands when you spin up a new VM and need to SSH into it. It queries the DHCP lease database or the guest agent for IP information.
$ virsh domifaddr webserver01
Name MAC address Protocol Address
--------------------------------------------------------------
vnet0 52:54:00:a1:b2:c3 ipv4 192.168.122.45/24
$ virsh domifaddr webserver01 --source agent
Name MAC address Protocol Address
--------------------------------------------------------------
lo 00:00:00:00:00:00 ipv4 127.0.0.1/8
eth0 52:54:00:a1:b2:c3 ipv4 192.168.122.45/24
eth0 52:54:00:a1:b2:c3 ipv6 fe80::5054:ff:fea1:b2c3/64
Attach and Detach Network Interfaces
Add or remove network interfaces on the fly. This is particularly useful when migrating a VM to a different network segment.
$ virsh attach-interface webserver01 bridge br1 --model virtio --persistent
Interface attached successfully
$ virsh detach-interface webserver01 bridge --mac 52:54:00:d4:e5:f6 --persistent
Interface detached successfully
5. Snapshots
Snapshots capture the state of a VM at a point in time. They are invaluable before applying patches, running upgrades, or testing configuration changes. For detailed coverage of snapshot strategies, see our guide on managing KVM virtual machines with virsh.
Create and List Snapshots
$ virsh snapshot-create-as webserver01 --name "pre-upgrade-2025" \
--description "Before kernel upgrade"
Domain snapshot pre-upgrade-2025 created
$ virsh snapshot-list webserver01
Name Creation Time State
-------------------------------------------------------------
pre-upgrade-2025 2025-09-15 14:30:22 +0000 running
baseline-config 2025-08-01 09:00:00 +0000 shutoff
Revert and Delete Snapshots
Reverting rolls the VM back to the exact state captured in the snapshot. The current state is lost unless you snapshot it first. Always verify which snapshot you are reverting to before running the command.
$ virsh snapshot-revert webserver01 pre-upgrade-2025
Domain snapshot pre-upgrade-2025 reverted
$ virsh snapshot-delete webserver01 pre-upgrade-2025
Domain snapshot pre-upgrade-2025 deleted
Keep in mind that internal snapshots on qcow2 images grow the file size over time and can hurt I/O performance. Clean up old snapshots regularly.
6. Console Access
When networking is down or not yet configured on a guest, you need console access to troubleshoot. Virsh provides multiple options.
Serial Console
This connects to the serial console of the guest. The guest OS must have a serial console configured (for example, adding console=ttyS0,115200 to the kernel boot parameters). Press Ctrl+] to disconnect.
$ virsh console webserver01
Connected to domain 'webserver01'
Escape character is ^]
Ubuntu 22.04.3 LTS webserver01 ttyS0
webserver01 login:
VNC Display and Screenshots
If the guest uses a graphical console, find the VNC display port and connect with any VNC client. You can also capture a screenshot of the current display directly from the command line.
$ virsh vncdisplay webserver01
127.0.0.1:0
$ virsh screenshot webserver01 /tmp/webserver01-screen.ppm
Screenshot saved to /tmp/webserver01-screen.ppm
7. Live Migration
Live migration moves a running VM from one KVM host to another with minimal downtime. Both hosts must have shared storage (or you use --copy-storage-all), compatible CPU models, and SSH key-based authentication configured between them.
$ virsh migrate --live --persistent --tunnelled webserver01 \
qemu+ssh://kvmhost02.example.com/system
Migration completed successfully
$ virsh migrate --live --persistent --copy-storage-all webserver01 \
qemu+ssh://kvmhost02.example.com/system --verbose
Migration: [100 %]
The --tunnelled flag encrypts the migration traffic through the libvirt connection. Use it when migrating across untrusted networks. The --persistent flag ensures the VM definition is created on the destination host. Without it, the VM becomes transient on the target and disappears on shutdown.
For large memory VMs, you may need to increase the migration bandwidth and set a downtime tolerance:
$ virsh migrate-setmaxdowntime webserver01 500
$ virsh migrate-setspeed webserver01 1000
8. Resource Management
One of the key advantages of virtualization is the ability to adjust resources without rebuilding a machine. Virsh lets you tune CPU, memory, and other resources on the fly or in the persistent configuration.
CPU Management
You can hot-add vCPUs to a running VM (if the guest OS supports it) or change the persistent configuration for next boot. The maximum must be set in the VM definition first.
$ virsh setvcpus webserver01 6 --live
$ virsh setvcpus webserver01 6 --config
$ virsh vcpucount webserver01
maximum config 8
maximum live 8
current config 6
current live 6
$ virsh cpu-stats webserver01
CPU0:
cpu_time: 45230000000 ns
user_time: 32100000000 ns
system_time: 13130000000 ns
CPU1:
cpu_time: 38900000000 ns
user_time: 27800000000 ns
system_time: 11100000000 ns
Memory Management
Memory ballooning allows you to adjust guest memory without a reboot, provided the balloon driver is loaded in the guest. Set the maximum first in the config, then adjust the current allocation.
$ virsh setmaxmem webserver01 16G --config
$ virsh setmem webserver01 12G --live
$ virsh memtune webserver01
hard_limit : unlimited
soft_limit : unlimited
swap_hard_limit: unlimited
min_guarantee : 0
$ virsh memtune webserver01 --hard-limit 16777216 --soft-limit 8388608
The memtune values are in KiB. Setting a hard_limit prevents the VM’s qemu process from consuming more memory than specified, which is useful for preventing OOM situations on the host.
9. Cloning Virtual Machines
Cloning creates an identical copy of an existing VM with a new name, new UUID, and new MAC addresses. The source VM must be shut down before cloning.
$ virt-clone --original webserver01 --name webserver02 \
--file /var/lib/libvirt/images/webserver02.qcow2
Allocating 'webserver02.qcow2' | 50 GB 00:02:15
Clone 'webserver02' created successfully.
$ virsh list --all | grep webserver
1 webserver01 running
- webserver02 shut off
After cloning, always boot the new VM and update the hostname, static IP addresses, and any host-specific identifiers like machine-id. On systemd-based systems, regenerate the machine ID:
$ rm /etc/machine-id && systemd-machine-id-setup
For creating VM templates and automated provisioning, check our guide on creating KVM VMs with virt-install.
10. Autostart and Boot Order
Production VMs should be set to autostart so they come back up automatically after a host reboot. This is easy to forget and causes unnecessary downtime during planned maintenance.
$ virsh autostart webserver01
Domain 'webserver01' marked as autostarted
$ virsh autostart --disable testvm02
Domain 'testvm02' unmarked as autostarted
$ virsh list --all --autostart
Id Name State
---------------------------------
1 webserver01 running
3 dbserver01 running
To change the boot order (for example, to boot from a CD-ROM for OS installation), edit the VM’s XML and adjust the <boot> elements under <os>:
$ virsh edit webserver01
# In the editor, modify the <os> section:
# <os>
# <boot dev='cdrom'/>
# <boot dev='hd'/>
# </os>
Domain 'webserver01' XML configuration edited.
11. XML Editing and Configuration
Every VM in libvirt is defined by an XML document. Understanding how to work with this XML is essential for anything beyond basic operations. The virsh edit command opens the VM’s XML in your default editor with validation on save.
$ EDITOR=vim virsh edit webserver01
When you save and exit, libvirt validates the XML and applies the changes. If the XML is malformed, it will reject the changes and let you re-edit. This is safer than manually editing files in /etc/libvirt/qemu/.
To create a VM from a standalone XML file or re-import a backed-up configuration:
$ virsh define /tmp/webserver01-backup.xml
Domain 'webserver01' defined from /tmp/webserver01-backup.xml
$ virsh create /tmp/webserver01-backup.xml
Domain 'webserver01' created from /tmp/webserver01-backup.xml
The difference between define and create is important. Define registers the VM persistently without starting it. Create starts the VM immediately but makes it transient, meaning the definition is lost when the VM shuts down. In production, always use define followed by start.
12. Useful One-Liners for Daily Admin
These are the shell one-liners I keep in my notes and use constantly. They combine virsh with standard Unix tools to handle bulk operations and quick reporting.
Start all VMs that are currently shut off:
$ for vm in $(virsh list --all --state-shutoff --name); do virsh start "$vm"; done
Gracefully shut down all running VMs:
$ for vm in $(virsh list --state-running --name); do virsh shutdown "$vm"; done
List all VMs with their disk usage:
$ for vm in $(virsh list --all --name); do
echo "=== $vm ==="
virsh domblkinfo "$vm" vda 2>/dev/null
done
Get IP addresses for all running VMs:
$ for vm in $(virsh list --state-running --name); do
echo "$vm: $(virsh domifaddr "$vm" | awk 'NR>2 && NF{print $4}')"
done
Export XML backups for all VMs:
$ mkdir -p /root/vm-xml-backups
$ for vm in $(virsh list --all --name); do
virsh dumpxml "$vm" > "/root/vm-xml-backups/${vm}.xml"
done
Find VMs consuming the most CPU time:
$ virsh list --state-running --name | while read vm; do
cpu=$(virsh dominfo "$vm" | awk '/CPU time/{print $3}')
echo "$cpu $vm"
done | sort -rn | head -10
Check which VMs do NOT have autostart enabled:
$ virsh list --all --name --no-autostart
Quick Reference Table
For quick lookups, here are the most common virsh operations in one place:
| Task | Command |
|---|---|
| List all VMs | virsh list --all |
| Start a VM | virsh start <name> |
| Graceful shutdown | virsh shutdown <name> |
| Force power off | virsh destroy <name> |
| Get VM details | virsh dominfo <name> |
| Get guest IP | virsh domifaddr <name> |
| Create snapshot | virsh snapshot-create-as <name> --name <snap> |
| Revert snapshot | virsh snapshot-revert <name> <snap> |
| Live migrate | virsh migrate --live <name> <dest-uri> |
| Set vCPUs | virsh setvcpus <name> <count> --live |
| Set memory | virsh setmem <name> <size> --live |
| Enable autostart | virsh autostart <name> |
| Dump XML config | virsh dumpxml <name> |
| Edit VM config | virsh edit <name> |
| Clone a VM | virt-clone --original <name> --name <new> --auto-clone |
Final Notes
Virsh is the single most important tool in a KVM administrator’s workflow. Every operation you can perform through virt-manager or a web UI ultimately translates to a virsh or libvirt API call underneath. Learning these commands thoroughly will make you faster, give you better control over your hypervisors, and let you automate anything through simple shell scripts.
A few habits that have served me well over the years: always dump the XML before editing a VM, always use --persistent when making live changes you want to keep, and always set autostart on production VMs. These three practices alone will prevent the majority of “it was working until we rebooted the host” incidents.
For the full virsh command reference, run virsh help or virsh help <command> for detailed usage on any specific subcommand.





































































Great job!!
Very helpful
Thanks for share it
Regards
Thanks a lot for positive comments.
Thanks for sharing the comprehensive virsh commands compilation.
This virsh commands cheatsheet sounds incredibly useful for managing KVM guests.
I found it really interesting how virsh, via Libvirt, supports such a wide array of hypervisors beyond KVM, like Xen, VirtualBox, and VMware vSphere ESX.
Appreciated! Nice post