QEMU Monitor Console and QMP Protocol: Control, Debug, and Inject Errors into KVM VMs from the Hypervisor Layer

Virtualization tutorial - IT technology blog
Virtualization tutorial - IT technology blog

You’re managing a running VM and need to debug something without SSH-ing into the guest? Or want to test how your application reacts when the disk suddenly fails? QEMU Monitor Console and QMP Protocol let you do exactly that — directly from the hypervisor layer, completely invisible to the guest OS.

Quick Start — Connect to QEMU Monitor in 5 Minutes

If you’re launching a VM manually with QEMU/KVM, add these two options to your startup command:

qemu-system-x86_64 \
  -monitor unix:/tmp/qemu-monitor.sock,server,nowait \
  -qmp unix:/tmp/qemu-qmp.sock,server,nowait \
  -drive file=/path/to/disk.qcow2,if=virtio \
  -m 2048 -smp 2

Connect to the monitor using socatnc often buffers commands incorrectly on Ubuntu, while socat handles readline much better:

socat readline UNIX-CONNECT:/tmp/qemu-monitor.sock

The (qemu) prompt appears — you’re inside the QEMU Monitor. Try a few commands right away:

(qemu) info status
(qemu) info cpus
(qemu) info block
(qemu) stop
(qemu) cont

If your VM runs through libvirt, use virsh to issue commands without opening an interactive session:

virsh qemu-monitor-command --hmp myvm "info status"
virsh qemu-monitor-command --hmp myvm "info block"

What Is QEMU Monitor Console and When Should You Use It?

Think of it as a backdoor into the QEMU process itself — not into the guest OS. The guest receives no signal whatsoever when you interact through the monitor, even if you’re stopping the CPU or dumping its entire RAM.

There are two protocols for talking to the monitor:

  • HMP (Human Monitor Protocol) — text commands, human-readable, great for quick debugging
  • QMP (QEMU Machine Protocol) — JSON-based, designed for scripting and automation

I run a homelab with Proxmox VE managing 12 VMs and containers — it’s my playground for testing everything before pushing to production. And there are situations where SSH-ing into the guest is simply not an option:

  • VM is completely frozen, not accepting SSH, but the QEMU process is still alive
  • Need a memory snapshot to analyze RAM state without interrupting the guest
  • Want to inject disk errors to verify whether disaster recovery scripts actually work
  • Debugging network packets at the virtual NIC layer before they reach the guest kernel

QMP Protocol — Automate with JSON and Python

QMP returns JSON for every response. Once parsed, you get a clean dict immediately — no regex, no manual string splitting like with HMP.

Connect to QMP Manually

socat - UNIX-CONNECT:/tmp/qemu-qmp.sock

The server sends a greeting immediately. You must send qmp_capabilities before issuing any commands:

{ "execute": "qmp_capabilities" }
{ "execute": "query-status" }

Python Script to Communicate with QMP

Instead of typing JSON by hand, a small wrapper makes life much easier:

import socket
import json

class QMPClient:
    def __init__(self, sock_path):
        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.sock.settimeout(10)
        self.sock.connect(sock_path)
        self._recv()  # greeting
        self.execute("qmp_capabilities")

    def _recv(self):
        data = b""
        while True:
            chunk = self.sock.recv(4096)
            data += chunk
            try:
                return json.loads(data.decode())
            except json.JSONDecodeError:
                continue

    def execute(self, cmd, **kwargs):
        payload = {"execute": cmd}
        if kwargs:
            payload["arguments"] = kwargs
        self.sock.sendall(json.dumps(payload).encode() + b"\n")
        return self._recv()

# Usage
qmp = QMPClient("/tmp/qemu-qmp.sock")

status = qmp.execute("query-status")
print(status)  # {"return": {"status": "running", "running": true}}

qmp.execute("stop")
qmp.execute("cont")

Injecting Errors and Debugging from the Hypervisor Layer

Pause a VM Like a Debugger Breakpoint

Stop the VM at a specific moment to observe its entire state — everything freezes in place, from CPU registers to memory mappings:

(qemu) stop
(qemu) info registers      # CPU registers at the point of suspension
(qemu) info mem            # memory mapping
(qemu) x /10i $rip         # disassemble 10 instructions from instruction pointer
(qemu) cont                # resume execution

Dump Memory for Forensic Analysis

# Via HMP
(qemu) dump-guest-memory -z /tmp/vm-memory.dump
# Via QMP
qmp.execute("dump-guest-memory",
    paging=False,
    protocol="file:/tmp/vm-memory.dump",
    format="elf"
)

The dump file can be opened with Volatility to find running processes, open file handles, or any artifact in RAM. I used this technique to analyze a VM suspected of having a rootkit installed — after dumping, I ran volatility3 -f vm-memory.dump linux.pslist and found a hidden process masquerading as kworker/1:2H with an abnormal parent PID. The entire investigation completed with volatile data intact, and the machine was never shut down once.

Inject Disk Errors to Test Disaster Recovery

This is my most frequently used use case — verifying that backup scripts can actually recover when a disk fails:

# List block devices
(qemu) info block
# Output: drive-scsi0-0-0-0: /var/lib/vz/images/100/vm-100-disk-0.qcow2

# Throttle I/O down to near zero to simulate a slow/failing disk
(qemu) block_set_io_throttle drive-scsi0-0-0-0 1 0 1 0 0 0

The six numbers limit respectively: total bandwidth (bytes/s), read bandwidth, write bandwidth, total iops, read iops, write iops — a value of 0 means no limit is applied for that direction. Setting bandwidth to 1 byte/s means the disk is operational but extremely slow, enough to trigger timeouts and test the application’s retry logic.

To inject I/O errors at a lower level, use the blkdebug driver when starting the VM:

qemu-system-x86_64 \
  -drive file=blkdebug::/path/to/disk.qcow2,if=virtio,format=qcow2 \
  -m 2048

Live Snapshot Without Shutting Down the VM

# Save the entire state (CPU + RAM + disk)
(qemu) savevm checkpoint-before-test

# List snapshots
(qemu) info snapshots

# Revert to a previous state
(qemu) loadvm checkpoint-before-test

Note: savevm creates an internal QEMU snapshot, which is different from a libvirt snapshot. The snapshot data is stored directly inside the qcow2 image.

Capture Network Packets at the Virtual NIC

# Enable packet capture on the virtual interface (netdev id comes from startup config)
(qemu) object_add filter-dump,id=f1,netdev=net0,file=/tmp/vm-traffic.pcap

# Disable when done
(qemu) object_del f1

This pcap file opens normally in Wireshark. The beauty here is that you see exactly what enters the virtual NIC — before iptables or any firewall rule inside the guest gets involved. Use it to separate two completely different questions: “is traffic reaching the VM” and “is the VM actually processing that traffic.”

Practical Tips for Working with QEMU Monitor

Find the socket path when you don’t know where it is:

ps aux | grep qemu | grep -o 'qmp [^ ]*'
# Or with libvirt
virsh dumpxml myvm | grep -i monitor

QMP over TCP for remote control:

qemu-system-x86_64 \
  -qmp tcp:127.0.0.1:4444,server,nowait \
  ...

# Connect (only expose this port externally behind a firewall or tunnel — QMP has no auth)
socat - TCP:127.0.0.1:4444

One-liner with virsh for scripting:

# HMP command
virsh qemu-monitor-command --hmp myvm "info block"

# QMP command (JSON)
virsh qemu-monitor-command myvm '{"execute": "query-block"}'

Check if a VM is still alive when it’s hung:

# If the monitor still responds, the QEMU process is alive even if the guest has hung
virsh qemu-monitor-command --hmp myvm "info status"

The monitor console doesn’t replace SSH or standard monitoring tools. But when everything else stops working — VM hard-locked, SSH timing out, agent not responding — the monitor is still there. Memory dump in under 30 seconds. Disk throttling to test recovery without needing real hardware failure. Once you get comfortable with it, you’ll find that many VM problems that seemed difficult are actually solvable in just a few minutes.

Share: