diff --git a/qemu-config.c b/qemu-config.c
index a23b125..c3203c8 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -224,6 +224,24 @@ QemuOptsList qemu_global_opts = {
     },
 };
 
+QemuOptsList qemu_mon_opts = {
+    .name = "mon",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
+    .desc = {
+        {
+            .name = "mode",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "chardev",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "default",
+            .type = QEMU_OPT_BOOL,
+        },
+        { /* end if list */ }
+    },
+};
+
 static QemuOptsList *lists[] = {
     &qemu_drive_opts,
     &qemu_chardev_opts,
@@ -232,6 +250,7 @@ static QemuOptsList *lists[] = {
     &qemu_net_opts,
     &qemu_rtc_opts,
     &qemu_global_opts,
+    &qemu_mon_opts,
     NULL,
 };
 
diff --git a/qemu-config.h b/qemu-config.h
index 6246e76..34dfadc 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -7,6 +7,7 @@ extern QemuOptsList qemu_device_opts;
 extern QemuOptsList qemu_netdev_opts;
 extern QemuOptsList qemu_net_opts;
 extern QemuOptsList qemu_rtc_opts;
+extern QemuOptsList qemu_mon_opts;
 
 int qemu_set_option(const char *str);
 int qemu_global_option(const char *str);
diff --git a/vl.c b/vl.c
index 701b687..11910ac 100644
--- a/vl.c
+++ b/vl.c
@@ -172,9 +172,6 @@ int main(int argc, char **argv)
 
 #define DEFAULT_RAM_SIZE 128
 
-/* Maximum number of monitor devices */
-#define MAX_MONITOR_DEVICES 10
-
 static const char *data_dir;
 const char *bios_name = NULL;
 /* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
@@ -211,7 +208,6 @@ int no_quit = 0;
 CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
-CharDriverState *monitor_hds[MAX_MONITOR_DEVICES];
 #ifdef TARGET_I386
 int win2k_install_hack = 0;
 int rtc_td_hack = 0;
@@ -4630,13 +4626,85 @@ static int chardev_init_func(QemuOpts *opts, void *opaque)
     return 0;
 }
 
+static int mon_init_func(QemuOpts *opts, void *opaque)
+{
+    CharDriverState *chr;
+    const char *chardev;
+    const char *mode;
+    int flags;
+
+    qemu_opts_print(opts, NULL);
+
+    mode = qemu_opt_get(opts, "mode");
+    if (mode == NULL) {
+        mode = "readline";
+    }
+    if (strcmp(mode, "readline") == 0) {
+        flags = MONITOR_USE_READLINE;
+    } else if (strcmp(mode, "control") == 0) {
+        flags = MONITOR_USE_CONTROL;
+    } else {
+        fprintf(stderr, "unknown monitor mode \"%s\"\n", mode);
+        exit(1);
+    }
+
+    if (qemu_opt_get_bool(opts, "default", 0))
+        flags |= MONITOR_IS_DEFAULT;
+
+    chardev = qemu_opt_get(opts, "chardev");
+    chr = qemu_chr_find(chardev);
+    if (chardev == NULL) {
+        fprintf(stderr, "chardev \"%s\" not found\n", chardev);
+        exit(1);
+    }
+
+    monitor_init(chr, flags);
+    return 0;
+}
+
+static void monitor_parse(const char *optarg)
+{
+    static int monitor_device_index = 0;
+    QemuOpts *opts;
+    const char *p;
+    char label[32];
+    int def = 0;
+
+    if (strstart(optarg, "chardev:", &p)) {
+        snprintf(label, sizeof(label), "%s", p);
+    } else {
+        if (monitor_device_index) {
+            snprintf(label, sizeof(label), "monitor%d",
+                     monitor_device_index);
+        } else {
+            snprintf(label, sizeof(label), "monitor");
+            def = 1;
+        }
+        opts = qemu_chr_parse_compat(label, optarg);
+        if (!opts) {
+            fprintf(stderr, "fixme #1\n");
+            exit(1);
+        }
+    }
+
+    opts = qemu_opts_create(&qemu_mon_opts, label, 1);
+    if (!opts) {
+        fprintf(stderr, "fixme #2\n");
+        exit(1);
+    }
+    qemu_opt_set(opts, "mode", "readline");
+    qemu_opt_set(opts, "chardev", label);
+    if (def)
+        qemu_opt_set(opts, "default", "on");
+    monitor_device_index++;
+}
+
 struct device_config {
     enum {
         DEV_USB,       /* -usbdevice   */
         DEV_BT,        /* -bt          */
         DEV_SERIAL,    /* -serial      */
         DEV_PARALLEL,  /* -parallel    */
-        DEV_MONITOR,   /* -monitor     */
     } type;
     const char *cmdline;
     QTAILQ_ENTRY(device_config) next;
@@ -4712,32 +4780,6 @@ static int parallel_parse(const char *devname)
     return 0;
 }
 
-static int monitor_parse(const char *devname)
-{
-    static int index = 0;
-    char label[32];
-
-    if (strcmp(devname, "none") == 0)
-        return 0;
-    if (index == MAX_MONITOR_DEVICES) {
-        fprintf(stderr, "qemu: too many monitor devices\n");
-        exit(1);
-    }
-    if (index == 0) {
-        snprintf(label, sizeof(label), "monitor");
-    } else {
-        snprintf(label, sizeof(label), "monitor%d", index);
-    }
-    monitor_hds[index] = qemu_chr_open(label, devname, NULL);
-    if (!monitor_hds[index]) {
-        fprintf(stderr, "qemu: could not open monitor device '%s'\n",
-                devname);
-        return -1;
-    }
-    index++;
-    return 0;
-}
-
 int main(int argc, char **argv, char **envp)
 {
     const char *gdbstub_dev = NULL;
@@ -5241,7 +5283,7 @@ int main(int argc, char **argv, char **envp)
                     break;
                 }
             case QEMU_OPTION_monitor:
-                add_device_config(DEV_MONITOR, optarg);
+                monitor_parse(optarg);
                 default_monitor = 0;
                 break;
             case QEMU_OPTION_chardev:
@@ -5572,7 +5614,7 @@ int main(int argc, char **argv, char **envp)
             if (default_serial)
                 add_device_config(DEV_SERIAL, "stdio");
             if (default_monitor)
-                add_device_config(DEV_MONITOR, "stdio");
+                monitor_parse("stdio");
         }
     } else {
         if (default_serial)
@@ -5580,7 +5622,7 @@ int main(int argc, char **argv, char **envp)
         if (default_parallel)
             add_device_config(DEV_PARALLEL, "vc:80Cx24C");
         if (default_monitor)
-            add_device_config(DEV_MONITOR, "vc:80Cx24C");
+            monitor_parse("vc:80Cx24C");
     }
     if (default_vga)
         vga_interface_type = VGA_CIRRUS;
@@ -5774,8 +5816,6 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
-    if (foreach_device_config(DEV_MONITOR, monitor_parse) < 0)
-        exit(1);
     if (foreach_device_config(DEV_SERIAL, serial_parse) < 0)
         exit(1);
     if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0)
@@ -5900,13 +5940,8 @@ int main(int argc, char **argv, char **envp)
 
     text_consoles_set_display(display_state);
 
-    for (i = 0; i < MAX_MONITOR_DEVICES; i++) {
-        if (monitor_hds[i]) {
-            monitor_init(monitor_hds[i],
-                         MONITOR_USE_READLINE |
-                         ((i == 0) ? MONITOR_IS_DEFAULT : 0));
-        }
-    }
+    if (qemu_opts_foreach(&qemu_mon_opts, mon_init_func, NULL, 1) != 0)
+        exit(1);
 
     if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
         fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n",
