diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h
index 1e694b5..f821781 100644
--- a/include/qapi/qmp/dispatch.h
+++ b/include/qapi/qmp/dispatch.h
@@ -15,6 +15,7 @@
 #define QAPI_QMP_DISPATCH_H
 
 #include "qemu/queue.h"
+#include "qapi-types.h"
 
 typedef void (QmpCommandFunc)(QDict *, QObject **, Error **);
 
@@ -31,12 +32,14 @@ typedef struct QmpCommand
     QmpCommandOptions options;
     QTAILQ_ENTRY(QmpCommand) node;
     bool enabled;
+    const RunState *valid_runstates;
 } QmpCommand;
 
 typedef QTAILQ_HEAD(QmpCommandList, QmpCommand) QmpCommandList;
 
 void qmp_register_command(QmpCommandList *cmds, const char *name,
-                          QmpCommandFunc *fn, QmpCommandOptions options);
+                          QmpCommandFunc *fn, QmpCommandOptions options,
+                          const RunState valid_runstates[]);
 void qmp_unregister_command(QmpCommandList *cmds, const char *name);
 QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name);
 QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request);
diff --git a/monitor.c b/monitor.c
index fcb5386..2edc96c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -224,6 +224,25 @@ static mon_cmd_t mon_cmds[];
 static mon_cmd_t info_cmds[];
 
 QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
+const RunState cap_negotiation_valid_runstates[] = {
+    RUN_STATE_DEBUG,
+    RUN_STATE_INMIGRATE,
+    RUN_STATE_INTERNAL_ERROR,
+    RUN_STATE_IO_ERROR,
+    RUN_STATE_PAUSED,
+    RUN_STATE_POSTMIGRATE,
+    RUN_STATE_PRELAUNCH,
+    RUN_STATE_FINISH_MIGRATE,
+    RUN_STATE_RESTORE_VM,
+    RUN_STATE_RUNNING,
+    RUN_STATE_SAVE_VM,
+    RUN_STATE_SHUTDOWN,
+    RUN_STATE_SUSPENDED,
+    RUN_STATE_WATCHDOG,
+    RUN_STATE_GUEST_PANICKED,
+    RUN_STATE_COLO,
+    RUN_STATE_PRECONFIG,
+};
 
 Monitor *cur_mon;
 
@@ -1016,17 +1035,18 @@ void monitor_init_qmp_commands(void)
 
     qmp_register_command(&qmp_commands, "query-qmp-schema",
                          qmp_query_qmp_schema,
-                         QCO_NO_OPTIONS);
+                         QCO_NO_OPTIONS, NULL);
     qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
-                         QCO_NO_OPTIONS);
+                         QCO_NO_OPTIONS, NULL);
     qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
-                         QCO_NO_OPTIONS);
+                         QCO_NO_OPTIONS, NULL);
 
     qmp_unregister_commands_hack();
 
     QTAILQ_INIT(&qmp_cap_negotiation_commands);
     qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
-                         qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS);
+                         qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS,
+                         cap_negotiation_valid_runstates);
 }
 
 void qmp_qmp_capabilities(Error **errp)
diff --git a/qapi-schema.json b/qapi-schema.json
index 0262b9f..ee1053d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -219,7 +219,11 @@
 # Note: This example has been shortened as the real response is too long.
 #
 ##
-{ 'command': 'query-commands', 'returns': ['CommandInfo'] }
+{ 'command': 'query-commands', 'returns': ['CommandInfo'],
+  'runstates': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
+                 'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
+                 'running', 'save-vm', 'shutdown', 'suspended', 'watchdog',
+                 'guest-panicked', 'colo', 'preconfig' ] }
 
 ##
 # @LostTickPolicy:
@@ -1146,7 +1150,11 @@
 # <- { "return": {} }
 #
 ##
-{ 'command': 'cont' }
+{ 'command': 'cont',
+  'runstates': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
+                 'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
+                 'running', 'save-vm', 'shutdown', 'suspended', 'watchdog',
+                 'guest-panicked', 'colo', 'preconfig' ] }
 
 ##
 # @system_wakeup:
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index e31ac4b..26cba19 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -17,6 +17,7 @@
 #include "qapi/qmp/json-parser.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qjson.h"
+#include "sysemu/sysemu.h"
 
 static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
 {
@@ -65,6 +66,40 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
     return dict;
 }
 
+static bool is_cmd_permited(const QmpCommand *cmd, Error **errp)
+{
+    int i;
+    char *list = NULL;
+
+    /* Old commands that don't have explicit runstate in schema
+     * are permited to run except of at PRECONFIG stage
+     */
+    if (!cmd->valid_runstates) {
+        if (runstate_check(RUN_STATE_PRECONFIG)) {
+            const char *state = RunState_str(RUN_STATE_PRECONFIG);
+            error_setg(errp, "The command '%s' isn't valid in '%s'",
+                       cmd->name, state);
+            return false;
+        }
+        return true;
+    }
+
+    for (i = 0; cmd->valid_runstates[i] != RUN_STATE__MAX; i++) {
+        if (runstate_check(cmd->valid_runstates[i])) {
+            return true;
+        }
+    }
+
+    for (i = 0; cmd->valid_runstates[i] != RUN_STATE__MAX; i++) {
+        const char *state = RunState_str(cmd->valid_runstates[i]);
+        list = g_strjoin(", ", state, list, NULL);
+    }
+    error_setg(errp, "The command '%s' is valid only in '%s'", cmd->name, list);
+    g_free(list);
+
+    return false;
+}
+
 static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
                                 Error **errp)
 {
@@ -92,6 +127,10 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
         return NULL;
     }
 
+    if (!is_cmd_permited(cmd, errp)) {
+        return NULL;
+    }
+
     if (!qdict_haskey(dict, "arguments")) {
         args = qdict_new();
     } else {
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
index 5af484c..59a5b85 100644
--- a/qapi/qmp-registry.c
+++ b/qapi/qmp-registry.c
@@ -16,7 +16,8 @@
 #include "qapi/qmp/dispatch.h"
 
 void qmp_register_command(QmpCommandList *cmds, const char *name,
-                          QmpCommandFunc *fn, QmpCommandOptions options)
+                          QmpCommandFunc *fn, QmpCommandOptions options,
+                          const RunState valid_runstates[])
 {
     QmpCommand *cmd = g_malloc0(sizeof(*cmd));
 
@@ -24,6 +25,7 @@ void qmp_register_command(QmpCommandList *cmds, const char *name,
     cmd->fn = fn;
     cmd->enabled = true;
     cmd->options = options;
+    cmd->valid_runstates = valid_runstates;
     QTAILQ_INSERT_TAIL(cmds, cmd, node);
 }
 
diff --git a/qapi/run-state.json b/qapi/run-state.json
index d24a4e8..1c1c9b8 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -92,7 +92,11 @@
 #                  "status": "running" } }
 #
 ##
-{ 'command': 'query-status', 'returns': 'StatusInfo' }
+{ 'command': 'query-status', 'returns': 'StatusInfo',
+  'runstates': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
+                 'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
+                 'running', 'save-vm', 'shutdown', 'suspended', 'watchdog',
+                 'guest-panicked', 'colo', 'preconfig' ] }
 
 ##
 # @SHUTDOWN:
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index f89d748..659e167 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -192,17 +192,45 @@ out:
     return ret
 
 
-def gen_register_command(name, success_response):
+def gen_register_command(name, success_response, runstates):
     options = 'QCO_NO_OPTIONS'
     if not success_response:
         options = 'QCO_NO_SUCCESS_RESP'
 
-    ret = mcgen('''
-    qmp_register_command(cmds, "%(name)s",
-                         qmp_marshal_%(c_name)s, %(opts)s);
-''',
-                name=name, c_name=c_name(name),
-                opts=options)
+    if runstates is None:
+        ret = mcgen('''
+        qmp_register_command(cmds, "%(name)s",
+                             qmp_marshal_%(c_name)s, %(opts)s,
+                             NULL);
+        ''',
+                     name=name, c_name=c_name(name),
+                     opts=options)
+    else:
+        ret = mcgen('''
+        static const RunState qmp_valid_states_%(c_name)s[] = {
+'''
+                   , c_name=c_name(name))
+
+        for value in runstates:
+            ret += mcgen('''
+                    %(c_enum)s,
+'''
+                         , c_enum=c_enum_const('RunState', value))
+
+        ret += mcgen('''
+                    %(c_enum)s,
+                };
+'''
+                     , c_enum=c_enum_const('RunState', "_MAX"))
+
+        ret += mcgen('''
+                qmp_register_command(cmds, "%(name)s",
+                                     qmp_marshal_%(c_name)s, %(opts)s,
+                                     qmp_valid_states_%(c_name)s);
+        ''',
+                     name=name, c_name=c_name(name),
+                     opts=options)
+
     return ret
 
 
@@ -241,7 +269,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
         self._visited_ret_types = None
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, runstates):
         if not gen:
             return
         self.decl += gen_command_decl(name, arg_type, boxed, ret_type)
@@ -250,7 +278,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
             self.defn += gen_marshal_output(ret_type)
         self.decl += gen_marshal_decl(name)
         self.defn += gen_marshal(name, arg_type, boxed, ret_type)
-        self._regy += gen_register_command(name, success_response)
+        self._regy += gen_register_command(name, success_response, runstates)
 
 
 (input_file, output_dir, do_c, do_h, prefix, opts) = parse_command_line()
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 032bcea..ede86ac 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -154,7 +154,7 @@ const char %(c_name)s[] = %(c_string)s;
                                     for m in variants.variants]})
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, runstates):
         arg_type = arg_type or self._schema.the_empty_object_type
         ret_type = ret_type or self._schema.the_empty_object_type
         self._gen_json(name, 'command',
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 58f995b..5c5037e 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -919,7 +919,8 @@ def check_exprs(exprs):
         elif 'command' in expr:
             meta = 'command'
             check_keys(expr_elem, 'command', [],
-                       ['data', 'returns', 'gen', 'success-response', 'boxed'])
+                       ['data', 'returns', 'gen', 'success-response', 'boxed',
+                        'runstates'])
         elif 'event' in expr:
             meta = 'event'
             check_keys(expr_elem, 'event', [], ['data', 'boxed'])
@@ -1030,7 +1031,7 @@ class QAPISchemaVisitor(object):
         pass
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, runstates):
         pass
 
     def visit_event(self, name, info, arg_type, boxed):
@@ -1397,7 +1398,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
 
 class QAPISchemaCommand(QAPISchemaEntity):
     def __init__(self, name, info, doc, arg_type, ret_type,
-                 gen, success_response, boxed):
+                 gen, success_response, boxed, runstates):
         QAPISchemaEntity.__init__(self, name, info, doc)
         assert not arg_type or isinstance(arg_type, str)
         assert not ret_type or isinstance(ret_type, str)
@@ -1408,6 +1409,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
         self.gen = gen
         self.success_response = success_response
         self.boxed = boxed
+        self.runstates = runstates
 
     def check(self, schema):
         if self._arg_type_name:
@@ -1431,7 +1433,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
     def visit(self, visitor):
         visitor.visit_command(self.name, self.info,
                               self.arg_type, self.ret_type,
-                              self.gen, self.success_response, self.boxed)
+                              self.gen, self.success_response, self.boxed,
+                              self.runstates)
 
 
 class QAPISchemaEvent(QAPISchemaEntity):
@@ -1639,6 +1642,7 @@ class QAPISchema(object):
         gen = expr.get('gen', True)
         success_response = expr.get('success-response', True)
         boxed = expr.get('boxed', False)
+        runstates = expr.get('runstates')
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(
                 name, info, doc, 'arg', self._make_members(data, info))
@@ -1646,7 +1650,8 @@ class QAPISchema(object):
             assert len(rets) == 1
             rets = self._make_array_type(rets[0], info)
         self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
-                                           gen, success_response, boxed))
+                                           gen, success_response, boxed,
+                                           runstates))
 
     def _def_event(self, expr, info, doc):
         name = expr['event']
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index bf1c57b..d28594c 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -227,7 +227,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
                              body=texi_entity(doc, 'Members'))
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, runstates):
         doc = self.cur_doc
         if boxed:
             body = texi_body(doc)
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 1d2c250..a47d6f6 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -18,9 +18,9 @@ object Variant1
     member var1: str optional=False
 object Variant2
 command cmd q_obj_cmd-arg -> Object
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
 command cmd-boxed Object -> None
-   gen=True success_response=True boxed=True
+   gen=True success_response=True boxed=True, runstates=None
 object q_empty
 object q_obj_Variant1-wrapper
     member data: Variant1 optional=False
diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
index b5637cb..d9a272b 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -1,7 +1,7 @@
 enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
     prefix QTYPE
 command fooA q_obj_fooA-arg -> None
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
 object q_empty
 object q_obj_fooA-arg
     member bar1: str optional=False
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index 586795f..4b128d5 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,7 +1,7 @@
 enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
     prefix QTYPE
 command eins None -> None
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
 object q_empty
 command zwei None -> None
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 3b1e908..787c228 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -153,15 +153,15 @@ object __org.qemu_x-Union2
     tag __org.qemu_x-member1
     case __org.qemu_x-value: __org.qemu_x-Struct2
 command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
 command boxed-struct UserDefZero -> None
-   gen=True success_response=True boxed=True
+   gen=True success_response=True boxed=True, runstates=None
 command boxed-union UserDefNativeListUnion -> None
-   gen=True success_response=True boxed=True
+   gen=True success_response=True boxed=True, runstates=None
 command guest-get-time q_obj_guest-get-time-arg -> int
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
 command guest-sync q_obj_guest-sync-arg -> any
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
 object q_empty
 object q_obj_EVENT_C-arg
     member a: int optional=True
@@ -222,10 +222,10 @@ object q_obj_user_def_cmd2-arg
     member ud1a: UserDefOne optional=False
     member ud1b: UserDefOne optional=True
 command user_def_cmd None -> None
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
 command user_def_cmd0 Empty2 -> Empty2
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
 command user_def_cmd1 q_obj_user_def_cmd1-arg -> None
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
 command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
-   gen=True success_response=True boxed=False
+   gen=True success_response=True boxed=False, runstates=None
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index ac43d34..958576d 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -37,11 +37,11 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         self._print_variants(variants)
 
     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response, boxed):
+                      gen, success_response, boxed, runstates):
         print('command %s %s -> %s' % \
               (name, arg_type and arg_type.name, ret_type and ret_type.name))
-        print('   gen=%s success_response=%s boxed=%s' % \
-              (gen, success_response, boxed))
+        print('   gen=%s success_response=%s boxed=%s, runstates=%s' % \
+              (gen, success_response, boxed, runstates))
 
     def visit_event(self, name, info, arg_type, boxed):
         print('event %s %s' % (name, arg_type and arg_type.name))
