diff --git a/monitor.c b/monitor.c
index 3ced51d..f6dd64d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -704,6 +704,32 @@ static void do_info_qmp_mode(Monitor *mon, QObject **ret_data)
     *ret_data = qobject_from_jsonf("{ 'mode': %s }", mode);
 }
 
+static void do_qmp_switch_mode(Monitor *mon, const QDict *qdict,
+                               QObject **ret_data)
+{
+    const char *mode;
+
+    if (!monitor_ctrl_mode(mon)) {
+        return;
+    }
+
+    mode = qdict_get_str(qdict, "mode");
+
+    /*
+     * Check is simple, as this function can only run in
+     * handshake mode.
+     */
+
+    if (!strcmp(mode, "operational")) {
+        mon->mc->mode = QMODE_OPERATIONAL;
+    } else if (!strcmp(mode,  "handshake")) {
+        /* only handshake -> operational is allowed */
+        qemu_error_new(QERR_QMP_INVALID_MODE_TRANSITION);
+    } else {
+        qemu_error_new(QERR_QMP_INVALID_MODE_NAME, mode);
+    }
+}
+
 /**
  * do_info_commands(): List QMP available commands
  *
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index b51bb47..29155ce 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -1064,6 +1064,21 @@ STEXI
 Set the encrypted device @var{device} password to @var{password}
 ETEXI
 
+    {
+        .name       = "qmp_switch_mode",
+        .args_type  = "mode:s",
+        .params     = "qmp_switch_mode mode",
+        .help       = "switch QMP mode",
+        .flags      = HANDLER_HANDSHAKE_ONLY,
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_qmp_switch_mode,
+    },
+
+STEXI
+@item qmp_switch_mode @var{mode}
+Switch QMP to @var{mode}
+ETEXI
+
 STEXI
 @end table
 ETEXI
