diff --git a/hw/qxl.c b/hw/qxl.c
index 583a2d9..18c63ff 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -34,6 +34,7 @@
 
 #ifndef CONFIG_QXL_IO_CLIENT_MONITORS_CONFIG
 #define QXL_IO_CAPABILITIES_SET (QXL_IO_FLUSH_RELEASE + 2)
+#define QXL_IO_CLIENT_MONITORS_CONFIG_DONE (QXL_IO_FLUSH_RELEASE + 3)
 #endif
 
 /*
@@ -596,6 +597,8 @@ static const char *io_port_to_string(uint32_t io_port)
         [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
         [QXL_IO_MONITORS_CONFIG_ASYNC]  = "QXL_IO_MONITORS_CONFIG_ASYNC",
         [QXL_IO_CAPABILITIES_SET]       = "QXL_IO_CAPABILITIES_SET",
+        [QXL_IO_CLIENT_MONITORS_CONFIG_DONE] =
+                                          "QXL_IO_CLIENT_MONITORS_CONFIG_DONE",
     };
 
     if (io_port >= ARRAY_SIZE(io_port_to_string)) {
@@ -986,6 +989,64 @@ static void interface_set_client_capabilities(QXLInstance *sin,
 
 #endif
 
+#if defined(CONFIG_QXL_IO_CLIENT_MONITORS_CONFIG) \
+    && SPICE_SERVER_VERSION >= 0x000b05
+static int qxl_test_guest_cap(PCIQXLDevice *qxl, unsigned cap)
+{
+    int ind = cap / 8;
+    uint8_t mask = 1 << (cap & 7);
+
+    if (ind >= sizeof(qxl->ram->guest_capabilities)) {
+        return 0;
+    }
+    return qxl->ram->guest_capabilities[ind] & mask;
+}
+
+/* called from main context only */
+static void interface_client_monitors_config(QXLInstance *sin,
+                                        VDAgentMonitorsConfig *monitors_config)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
+    int i;
+
+    if (!qxl_test_guest_cap(qxl, QXL_GUEST_CAP_CLIENT_MONITORS_CONFIG_ISR)) {
+        trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id,
+                                                              monitors_config);
+        return;
+    }
+    if (qxl->client_monitors_config_isr_in_progress) {
+        trace_qxl_client_monitors_config_ignored_guest_busy(qxl->id,
+                                                            monitors_config);
+        return;
+    }
+    rom->client_monitors_config.count = monitors_config->num_of_monitors;
+    /* monitors_config->flags ignored */
+    if (rom->client_monitors_config.count >=
+            ARRAY_SIZE(rom->client_monitors_config.heads)) {
+        trace_qxl_client_monitors_config_capped(qxl->id,
+                                monitors_config->num_of_monitors,
+                                ARRAY_SIZE(rom->client_monitors_config.heads));
+        rom->client_monitors_config.count =
+            ARRAY_SIZE(rom->client_monitors_config.heads);
+    }
+    for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
+        VDAgentMonConfig *monitor = &monitors_config->monitors[i];
+        QXLURect *rect = &rom->client_monitors_config.heads[i];
+        /* monitor->depth ignored */
+        rect->left = monitor->x;
+        rect->top = monitor->y;
+        rect->right = monitor->x + monitor->width;
+        rect->bottom = monitor->y + monitor->height;
+    }
+    trace_qxl_interrupt_client_monitors_config(qxl->id,
+                        rom->client_monitors_config.count,
+                        rom->client_monitors_config.heads);
+    qxl->client_monitors_config_isr_in_progress = 1;
+    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
+}
+#endif
+
 static const QXLInterface qxl_interface = {
     .base.type               = SPICE_INTERFACE_QXL,
     .base.description        = "qxl gpu",
@@ -1010,6 +1071,10 @@ static const QXLInterface qxl_interface = {
 #if SPICE_SERVER_VERSION >= 0x000b04
     .set_client_capabilities = interface_set_client_capabilities,
 #endif
+#if SPICE_SERVER_VERSION >= 0x000b05 && \
+    defined(CONFIG_QXL_IO_CLIENT_MONITORS_CONFIG)
+    .client_monitors_config = interface_client_monitors_config,
+#endif
 };
 
 static void qxl_enter_vga_mode(PCIQXLDevice *d)
@@ -1604,6 +1669,16 @@ async_common:
     case QXL_IO_CAPABILITIES_SET:
         qxl_spice_guest_capabilities_set(d);
         break;
+    case QXL_IO_CLIENT_MONITORS_CONFIG_DONE:
+        trace_qxl_io_client_monitors_config_done(d->id);
+        if (!d->client_monitors_config_isr_in_progress) {
+            qxl_set_guest_bug(d,
+                "%s: unexpected QXL_IO_CLIENT_MONITORS_CONFIG_DONE\n",
+                __func__);
+        } else {
+            d->client_monitors_config_isr_in_progress = 0;
+        }
+        break;
     default:
         qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
     }
diff --git a/hw/qxl.h b/hw/qxl.h
index 5553824..a1ede3c 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -72,6 +72,8 @@ typedef struct PCIQXLDevice {
 
     QXLPHYSICAL        guest_monitors_config;
 
+    int                client_monitors_config_isr_in_progress;
+
     QemuMutex          track_lock;
 
     /* thread signaling */
diff --git a/trace-events b/trace-events
index 7a35f62..4ea7cdd 100644
--- a/trace-events
+++ b/trace-events
@@ -928,6 +928,7 @@ qxl_io_read_unexpected(int qid) "%d"
 qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)"
 qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d"
 qxl_io_capabilities_set(int qid, int caps_size, uint8_t *caps) "%d %d %p"
+qxl_io_client_monitors_config_done(int qid) "%d"
 qxl_memslot_add_guest(int qid, uint32_t slot_id, uint64_t guest_start, uint64_t guest_end) "%d %u: guest phys 0x%"PRIx64 " - 0x%" PRIx64
 qxl_post_load(int qid, const char *mode) "%d %s"
 qxl_pre_load(int qid) "%d"
@@ -968,6 +969,10 @@ qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dir
 qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d"
 qxl_send_events(int qid, uint32_t events) "%d %d"
 qxl_set_guest_bug(int qid) "%d"
+qxl_interrupt_client_monitors_config(int qid, int num_heads, void *heads) "%d %d %p"
+qxl_client_monitors_config_unsupported_by_guest(int qid, void *client_monitors_config) "%d %p"
+qxl_client_monitors_config_ignored_guest_busy(int qid, void *client_monitors_config) "%d %p"
+qxl_client_monitors_config_capped(int qid, int requested, int limit) "%d %d %d"
 
 # hw/qxl-render.c
 qxl_render_blit_guest_primary_initialized(void) ""
