diff --git a/monitor.c b/monitor.c
index 7536c1e..78fd33a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -357,6 +357,9 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
         case QEVENT_STOP:
             event_name = "STOP";
             break;
+        case QEVENT_VNC_DISCONNECT:
+            event_name = "VNC_DISCONNECT";
+            break;
         default:
             abort();
             break;
diff --git a/monitor.h b/monitor.h
index 6ed117a..e836dd6 100644
--- a/monitor.h
+++ b/monitor.h
@@ -20,6 +20,7 @@ typedef enum MonitorEvent {
     QEVENT_RESET,
     QEVENT_POWERDOWN,
     QEVENT_STOP,
+    QEVENT_VNC_DISCONNECT,
     QEVENT_MAX,
 } MonitorEvent;
 
diff --git a/vnc.c b/vnc.c
index f340d08..f2f0ef3 100644
--- a/vnc.c
+++ b/vnc.c
@@ -1068,6 +1068,29 @@ static void vnc_disconnect_start(VncState *vs)
     vs->csock = -1;
 }
 
+static void vnc_qmp_event(VncState *vs, MonitorEvent event)
+{
+    QDict *server;
+    QObject *data;
+
+    if (!vs->info) {
+        return;
+    }
+
+    server = qdict_new();
+    if (vnc_server_info_put(server) < 0) {
+        QDECREF(server);
+        return;
+    }
+
+    data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
+                              vs->info, QOBJECT(server));
+
+    monitor_protocol_event(event, data);
+
+    qobject_decref(data); /* will also free 'vs->info' */
+}
+
 static void vnc_disconnect_finish(VncState *vs)
 {
     if (vs->input.buffer) {
@@ -1078,6 +1101,9 @@ static void vnc_disconnect_finish(VncState *vs)
         qemu_free(vs->output.buffer);
         vs->output.buffer = NULL;
     }
+
+    vnc_qmp_event(vs, QEVENT_VNC_DISCONNECT);
+
 #ifdef CONFIG_VNC_TLS
     vnc_tls_client_cleanup(vs);
 #endif /* CONFIG_VNC_TLS */
@@ -1100,8 +1126,6 @@ static void vnc_disconnect_finish(VncState *vs)
     if (!vs->vd->clients)
         dcl->idle = 1;
 
-    qobject_decref(vs->info);
-
     vnc_remove_timer(vs->vd);
     qemu_free(vs);
 }
