virsh is the command-line management shell of libvirt, the standard toolkit for controlling virtual machines in Linux virtualization. It lets an administrator define, start, stop, migrate, snapshot and reconfigure guests on hypervisors such as KVM with QEMU, and it manages the storage pools and virtual networks those guests use.
Because virsh talks to the libvirt daemon rather than to the hypervisor directly, the same commands work on a local workstation and on a remote host reached over SSH. It is the scriptable counterpart of graphical tools such as virt-manager and GNOME Boxes, and it exposes nearly every option that libvirt supports.
How virsh communicates with libvirt
virsh is a client of the libvirt API. Each command opens a connection described by a connection URI, sends a request to a libvirt daemon (the monolithic libvirtd or the newer modular daemons such as virtqemud), and prints the result. The daemon in turn drives QEMU processes, configures cgroups, applies SELinux or AppArmor labels and sets up networking.
Every guest is described by an XML domain definition that lists CPUs, memory, disks, network interfaces and devices. virsh does not invent configuration; it reads, edits and submits this XML. Understanding the XML is therefore the key to using virsh beyond basic start and stop operations.
The connection URI decides which hypervisor and which privilege level virsh addresses, as the table shows.
| URI | Target | Typical use |
|---|---|---|
qemu:///system | System-wide KVM guests | Servers and shared hosts |
qemu:///session | Per-user unprivileged guests | Desktops, user-mode networking |
qemu+ssh://host/system | Remote host over SSH | Managing several hypervisors |
lxc:///system | libvirt LXC containers | Container domains via libvirt |
A frequent source of confusion is that `system` and `session` are separate worlds: a guest defined in one connection does not appear in the other. If virsh list --all shows nothing, the first check is the URI, set with -c or the LIBVIRT_DEFAULT_URI variable.
Core command groups
virsh organizes its several hundred subcommands into groups by object type: domains, storage pools and volumes, networks, interfaces, node devices, snapshots and secrets. Most daily work uses a small subset, summarized below.
| Command | Action | Notes |
|---|---|---|
list --all | Shows running and defined guests | Without --all only running ones |
define / undefine | Registers or removes a persistent guest | Undefine keeps disk images by default |
start / shutdown | Boots or gracefully stops a guest | Shutdown sends an ACPI request |
destroy | Forcibly stops a guest | Equivalent to pulling the power cord |
edit | Opens the domain XML in an editor | Validates XML before saving |
console | Attaches to the serial console | Exit with Ctrl plus ] |
snapshot-create-as | Creates a named snapshot | Needs qcow2 for internal snapshots |
migrate | Moves a guest to another host | Live migration with --live |
The name `destroy` is misleading for newcomers: it does not delete anything, it only performs a hard power-off. Deleting a guest is undefine, optionally with --remove-all-storage.
Beyond guests, virsh manages the resources guests depend on. pool-list, pool-define-as and vol-create-as handle storage pools and volumes, which may be directories of qcow2 files, LVM volume groups, iSCSI targets or Ceph RBD images. net-list, net-start and net-edit control virtual networks, such as the default NAT network with its built-in DHCP and DNS service on the virbr0 bridge.
Monitoring commands complete the picture. domstats, domblkstat and domifstat report CPU time, disk I/O and network counters per guest, while nodeinfo and capabilities describe what the host and hypervisor can offer, which is useful before planning CPU models or device passthrough with VFIO.
Persistent and transient guests
libvirt distinguishes persistent domains, whose XML is stored on the host and survives reboots, from transient domains, which exist only while running. virsh exposes this distinction directly through define and create.
Changes to a running guest also come in two flavors: live changes apply immediately but vanish at shutdown, while config changes apply at the next boot. Commands such as setmem, setvcpus and attach-device accept --live, --config or both.
| Flag | Applies to | Survives guest restart |
|---|---|---|
--live | Running guest only | No |
--config | Stored definition only | Yes, from next boot |
--live --config | Both at once | Yes |
--current | Whichever state the guest is in | Depends on that state |
Forgetting --config is the classic reason why a hot-added disk disappears after a reboot. Forgetting --live explains why a change seems to have no effect until the next restart.
virsh compared with other virtualization tools
virsh sits at a specific level in the Linux virtualization stack: above QEMU and KVM, beside graphical libvirt clients, below full platforms. Choosing between them depends on whether automation, convenience or cluster management matters most.
| Tool | Interface | Best suited for |
|---|---|---|
| virsh | Command line over libvirt | Scripting, servers, remote hosts |
| virt-manager | Graphical libvirt client | Interactive desktop management |
| virt-install | Command line, creation only | Provisioning new guests |
| QEMU directly | Raw command-line options | Testing and unusual device setups |
| Proxmox VE | Web platform with own tooling | Clusters without libvirt |
Running QEMU directly gives maximum control but bypasses libvirt’s security labeling, cgroup limits and lifecycle tracking. For production guests, virsh or another libvirt client is the safer route.
Pitfalls and good practice
Most virsh problems come from permissions, URIs and storage assumptions rather than from the tool itself. The following practices avoid the common traps.
- Use `virsh edit` instead of editing XML files under
/etc/libvirtby hand, because the daemon does not reread manually changed files. - Back up the domain XML with
virsh dumpxmlbefore major changes, so a guest can be redefined quickly. - Check guest agent availability before relying on
shutdown --mode agentor filesystem freeze for consistent snapshots. - Prefer external snapshots for large production disks, and remember that they must be merged back with
blockcommit. - Add administrators to the libvirt group rather than running every command as root on hosts that use polkit rules.
In simple terms
Imagine a building full of virtual computers and a building manager who holds every key. virsh is the way you give that manager instructions by typing short commands: start this computer, switch that one off, give this one more memory, move that one to another building.
Graphical tools do the same thing with buttons and windows. virsh is preferred when you want to repeat the same steps reliably, run them on a remote server, or put them in a script that works every night without anyone clicking.
A practical example
A university lab runs twelve KVM guests on two Linux hosts for student projects. Before each semester, the administrator uses a short shell script built on virsh: virsh snapshot-create-as takes a clean snapshot of every guest, and virsh setmem --config raises memory from 4 GiB to 8 GiB for the database course machines.
When one host needs a firmware update, the administrator runs virsh migrate --live for each guest to the second host over SSH, updates and reboots the first host, and migrates the guests back. Students notice only a brief pause of under a second, and at the end of the semester every guest is returned to its clean state with virsh snapshot-revert.