diff --git a/hmp-commands.hx b/hmp-commands.hx
index 9cea415..e5c1b14 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1639,6 +1639,8 @@ show qdev device model list
 show roms
 @item info tpm
 show the TPM device
+@item info mac-table [net client name]
+show the mac-table information for all nics (or for the given nic)
 @end table
 ETEXI
 
diff --git a/hmp.c b/hmp.c
index 4fb76ec..3e19df0 100644
--- a/hmp.c
+++ b/hmp.c
@@ -653,6 +653,77 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
     qapi_free_TPMInfoList(info_list);
 }
 
+void hmp_info_mac_table(Monitor *mon, const QDict *qdict)
+{
+    MacTableInfoList *table_list, *entry;
+    strList *str_entry;
+    bool has_name = qdict_haskey(qdict, "name");
+    const char *name = NULL;
+
+    if (has_name) {
+        name = qdict_get_str(qdict, "name");
+    }
+
+    table_list = qmp_query_mac_table(has_name, name, NULL);
+    entry = table_list;
+
+    while (entry) {
+        monitor_printf(mon, "%s:\n", entry->value->name);
+        if (entry->value->has_promisc) {
+            monitor_printf(mon, " \\ promisc: %s\n",
+                           entry->value->promisc ? "on" : "off");
+        }
+        if (entry->value->has_allmulti) {
+            monitor_printf(mon, " \\ allmulti: %s\n",
+                           entry->value->allmulti ? "on" : "off");
+        }
+        if (entry->value->has_alluni) {
+            monitor_printf(mon, " \\ alluni: %s\n",
+                           entry->value->alluni ? "on" : "off");
+        }
+        if (entry->value->has_nomulti) {
+            monitor_printf(mon, " \\ nomulti: %s\n",
+                           entry->value->nomulti ? "on" : "off");
+        }
+        if (entry->value->has_nouni) {
+            monitor_printf(mon, " \\ nouni: %s\n",
+                           entry->value->nouni ? "on" : "off");
+        }
+        if (entry->value->has_nobcast) {
+            monitor_printf(mon, " \\ nobcast: %s\n",
+                           entry->value->nobcast ? "on" : "off");
+        }
+        if (entry->value->has_multi_overflow) {
+            monitor_printf(mon, " \\ multi_overflow: %s\n",
+                           entry->value->multi_overflow ? "on" : "off");
+        }
+        if (entry->value->has_uni_overflow) {
+            monitor_printf(mon, " \\ uni_overflow: %s\n",
+                           entry->value->uni_overflow ? "on" : "off");
+        }
+
+        if (entry->value->has_unicast) {
+            str_entry = entry->value->unicast;
+            monitor_printf(mon, " \\ unicast:\n");
+            while (str_entry) {
+                monitor_printf(mon, "    %s\n", str_entry->value);
+                str_entry = str_entry->next;
+            }
+        }
+        if (entry->value->has_multicast) {
+            str_entry = entry->value->multicast;
+            monitor_printf(mon, " \\ multicast:\n");
+            while (str_entry) {
+                monitor_printf(mon, "    %s\n", str_entry->value);
+                str_entry = str_entry->next;
+            }
+        }
+
+        entry = entry->next;
+    }
+    qapi_free_MacTableInfoList(table_list);
+}
+
 void hmp_quit(Monitor *mon, const QDict *qdict)
 {
     monitor_suspend(mon);
diff --git a/hmp.h b/hmp.h
index 95fe76e..278c722 100644
--- a/hmp.h
+++ b/hmp.h
@@ -37,6 +37,7 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict);
 void hmp_info_pci(Monitor *mon, const QDict *qdict);
 void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
 void hmp_info_tpm(Monitor *mon, const QDict *qdict);
+void hmp_info_mac_table(Monitor *mon, const QDict *qdict);
 void hmp_quit(Monitor *mon, const QDict *qdict);
 void hmp_stop(Monitor *mon, const QDict *qdict);
 void hmp_system_reset(Monitor *mon, const QDict *qdict);
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index a9b8f53..e4b2358 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -194,6 +194,68 @@ static void virtio_net_set_link_status(NetClientState *nc)
     virtio_net_set_status(vdev, vdev->status);
 }
 
+static MacTableInfo *virtio_net_query_mactable(NetClientState *nc)
+{
+    VirtIONet *n = qemu_get_nic_opaque(nc);
+    MacTableInfo *info;
+    strList *str_list = NULL;
+    strList *entry;
+    int i;
+
+    info = g_malloc0(sizeof(*info));
+    info->name = g_strdup(nc->name);
+
+    info->promisc = n->promisc;
+    info->has_promisc = true;
+    info->allmulti = n->allmulti;
+    info->has_allmulti = true;
+    info->alluni = n->alluni;
+    info->has_alluni = true;
+    info->nomulti = n->nomulti;
+    info->has_nomulti = true;
+    info->nouni = n->nouni;
+    info->has_nouni = true;
+    info->nobcast = n->nobcast;
+    info->has_nobcast = true;
+    info->multi_overflow = n->mac_table.multi_overflow;
+    info->has_multi_overflow = true;
+    info->uni_overflow = n->mac_table.uni_overflow;
+    info->has_uni_overflow = true;
+
+    for (i = 0; i < n->mac_table.first_multi; i++) {
+        info->has_unicast = true;
+        entry = g_malloc0(sizeof(*entry));
+        entry->value = g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
+                                       n->mac_table.macs[i * ETH_ALEN],
+                                       n->mac_table.macs[i * ETH_ALEN + 1],
+                                       n->mac_table.macs[i * ETH_ALEN + 2],
+                                       n->mac_table.macs[i * ETH_ALEN + 3],
+                                       n->mac_table.macs[i * ETH_ALEN + 4],
+                                       n->mac_table.macs[i * ETH_ALEN + 5]);
+        entry->next = str_list;
+        str_list = entry;
+    }
+    info->unicast = str_list;
+
+    str_list = NULL;
+    for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
+        info->has_multicast = true;
+        entry = g_malloc0(sizeof(*entry));
+        entry->value = g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
+                                       n->mac_table.macs[i * ETH_ALEN],
+                                       n->mac_table.macs[i * ETH_ALEN + 1],
+                                       n->mac_table.macs[i * ETH_ALEN + 2],
+                                       n->mac_table.macs[i * ETH_ALEN + 3],
+                                       n->mac_table.macs[i * ETH_ALEN + 4],
+                                       n->mac_table.macs[i * ETH_ALEN + 5]);
+        entry->next = str_list;
+        str_list = entry;
+    }
+    info->multicast = str_list;
+
+    return info;
+}
+
 static void virtio_net_reset(VirtIODevice *vdev)
 {
     VirtIONet *n = VIRTIO_NET(vdev);
@@ -1255,6 +1317,7 @@ static NetClientInfo net_virtio_info = {
     .receive = virtio_net_receive,
         .cleanup = virtio_net_cleanup,
     .link_status_changed = virtio_net_set_link_status,
+    .query_mac_table = virtio_net_query_mactable,
 };
 
 static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx)
diff --git a/include/net/net.h b/include/net/net.h
index 43d85a1..c3ca4ea 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -49,6 +49,7 @@ typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int);
 typedef void (NetCleanup) (NetClientState *);
 typedef void (LinkStatusChanged)(NetClientState *);
 typedef void (NetClientDestructor)(NetClientState *);
+typedef MacTableInfo *(QueryMacTable)(NetClientState *);
 
 typedef struct NetClientInfo {
     NetClientOptionsKind type;
@@ -59,6 +60,7 @@ typedef struct NetClientInfo {
     NetCanReceive *can_receive;
     NetCleanup *cleanup;
     LinkStatusChanged *link_status_changed;
+    QueryMacTable *query_mac_table;
     NetPoll *poll;
 } NetClientInfo;
 
diff --git a/monitor.c b/monitor.c
index 9e51545..a01cdbd 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2765,6 +2765,14 @@ static mon_cmd_t info_cmds[] = {
         .mhandler.cmd = hmp_info_tpm,
     },
     {
+        .name       = "mac-table",
+        .args_type  = "name:s?",
+        .params     = "[net client name]",
+        .help       = "show the mac-table information for all nics (or"
+                      " for the given nic)",
+        .mhandler.cmd = hmp_info_mac_table,
+    },
+    {
         .name       = NULL,
     },
 };
diff --git a/net/net.c b/net/net.c
index 43a74e4..9ff3006 100644
--- a/net/net.c
+++ b/net/net.c
@@ -961,6 +961,44 @@ void print_net_client(Monitor *mon, NetClientState *nc)
                    nc->info_str);
 }
 
+MacTableInfoList *qmp_query_mac_table(bool has_name, const char *name,
+                                      Error **errp)
+{
+    NetClientState *nc;
+    MacTableInfoList *table_list = NULL, *last_entry = NULL;
+
+    QTAILQ_FOREACH(nc, &net_clients, next) {
+        MacTableInfoList *entry;
+        MacTableInfo *info;
+
+        if (nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC) {
+            continue;
+        }
+        if (has_name && strcmp(nc->name, name) != 0) {
+            continue;
+        }
+
+        if (nc->info->query_mac_table) {
+            info = nc->info->query_mac_table(nc);
+            entry = g_malloc0(sizeof(*entry));
+            entry->value = info;
+
+            if (!table_list) {
+                table_list = entry;
+            } else {
+                last_entry->next = entry;
+            }
+            last_entry = entry;
+        }
+    }
+
+    if (table_list == NULL) {
+        error_setg(errp, "invalid net client name: %s", name);
+    }
+
+    return table_list;
+}
+
 void do_info_network(Monitor *mon, const QDict *qdict)
 {
     NetClientState *nc, *peer;
diff --git a/qapi-schema.json b/qapi-schema.json
index 199744a..866650c 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3619,3 +3619,60 @@
             '*cpuid-input-ecx': 'int',
             'cpuid-register': 'X86CPURegister32',
             'features': 'int' } }
+
+# @MacTableInfo:
+#
+# Rx-mode information of mac-table for a net client.
+#
+# @name: the net client name
+#
+# @promisc: #optional promiscuous mode (default: false)
+#
+# @allmulti: #optional all multicast mode (default: false)
+#
+# @alluni: #optional all unicast mode (default: false)
+#
+# @nomulti: #optional no multicast mode (default: false)
+#
+# @nouni: #optional no unicast mode (default: false)
+#
+# @nobcast: #optional no broadcast mode (default: false)
+#
+# @multi_overflow: #optional multicast overflow mode (default: false)
+#
+# @uni_overflow: #optional unicast overflow mode (default: false)
+#
+# @unicast: #optional a list of unicast macaddr string
+#
+# @multicast: #optional a list of multicast macaddr string
+#
+# Since 1.6
+##
+{ 'type': 'MacTableInfo',
+  'data': {
+    'name':            'str',
+    '*promisc':        'bool',
+    '*allmulti':       'bool',
+    '*alluni':         'bool',
+    '*nomulti':        'bool',
+    '*nouni':          'bool',
+    '*nobcast':        'bool',
+    '*multi-overflow': 'bool',
+    '*uni-overflow':   'bool',
+    '*unicast':        ['str'],
+    '*multicast':      ['str'] }}
+
+##
+# @query-mac-table:
+#
+# Return mac-table information for all nics (or for the given nic).
+#
+# @name: #optional net client name
+#
+# Returns: list of @MacTableInfo for all nics (or for the given nic).
+#          Returns an error if the given @name doesn't exist.
+#
+# Since: 1.6
+##
+{ 'command': 'query-mac-table', 'data': { '*name': 'str' },
+  'returns': ['MacTableInfo'] }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ffd130e..66826ab 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2932,3 +2932,56 @@ Example:
 <- { "return": {} }
 
 EQMP
+    {
+        .name       = "query-mac-table",
+        .args_type  = "name:s?",
+        .mhandler.cmd_new = qmp_marshal_input_query_mac_table,
+    },
+
+SQMP
+query-mac-table
+---------------
+
+Show mac-table information.
+
+Returns a json-array of mac-table information for all nics (or for the
+given nic), returning an error if the given nic doesn't exist.
+
+Each array entry contains the following:
+
+- "name": net client name (jaso-string)
+- "promisc": promiscuous mode (json-bool, optional)
+- "allmulti": all multicast mode (json-bool, optional)
+- "alluni": all unicast mode (json-bool, optional)
+- "nomulti":no multicast mode (json-bool, optional)
+- "nouni": no unicast mode (json-bool, optional)
+- "nobcast": no broadcast mode (json-bool, optional)
+- "multi-overflow": multicast overflow mode (json-bool, optional)
+- "uni-overflow": unicast overflow mode (json-bool, optional)
+- "unicast": a jason-array of unicast macaddr string (optional)
+- "multicast": a jason-array of multicast macaddr string (optional)
+
+Example:
+
+-> { "execute": "query-mac-table", "arguments": { "name": "vnet0" }}
+<- { "return": [
+        {
+            "multi-overflow": false,
+            "name": "vnet0",
+            "uni-overflow": false,
+            "nobcast": false,
+            "promisc": true,
+            "multicast": [
+                "01:00:5e:00:00:01",
+                "33:33:00:00:00:01",
+                "33:33:ff:12:34:56"
+            ],
+            "nouni": false,
+            "nomulti": false,
+            "allmulti": false,
+            "alluni": false
+        }
+      ]
+   }
+
+EQMP
