diff --git a/hmp.c b/hmp.c
index 261843f7a2..35ad8c9716 100644
--- a/hmp.c
+++ b/hmp.c
@@ -2144,7 +2144,8 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict)
 void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
 {
     Error *err = NULL;
-    MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err);
+    MemoryDeviceInfoList *info_list =
+        qmp_query_memory_devices(true, MEMORY_DEVICE_TYPE_DIMM, &err);
     MemoryDeviceInfoList *info;
     MemoryDeviceInfo *value;
     PCDIMMDeviceInfo *di;
diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
index 0d3e17e94c..811efda869 100644
--- a/hw/mem/nvdimm.c
+++ b/hw/mem/nvdimm.c
@@ -178,3 +178,41 @@ static void nvdimm_register_types(void)
 }
 
 type_init(nvdimm_register_types)
+
+static int qmp_nvdimm_device_info(Object *obj, NVDIMMDeviceInfo *di)
+{
+    if (!object_dynamic_cast(obj, TYPE_NVDIMM)) {
+        return 1;
+    }
+
+    if (qmp_pc_dimm_device_info(obj, (PCDIMMDeviceInfo *)di)) {
+        return 1;
+    }
+
+    di->label_size = object_property_get_int(obj, "label-size", NULL);
+
+    return 0;
+}
+
+int qmp_nvdimm_device_list(Object *obj, void *opaque)
+{
+    MemoryDeviceInfoList ***prev = opaque;
+    NVDIMMDeviceInfo *di = g_new0(NVDIMMDeviceInfo, 1);
+
+    if (qmp_nvdimm_device_info(obj, di)) {
+        g_free(di);
+    } else {
+        MemoryDeviceInfoList *elem = g_new0(MemoryDeviceInfoList, 1);
+        MemoryDeviceInfo *info = g_new0(MemoryDeviceInfo, 1);
+
+        info->type = MEMORY_DEVICE_TYPE_NVDIMM;
+        info->u.nvdimm.data = di;
+        elem->value = info;
+        elem->next = NULL;
+        **prev = elem;
+        *prev = &elem->next;
+    }
+
+    object_child_foreach(obj, qmp_nvdimm_device_list, opaque);
+    return 0;
+}
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index 69c5784252..40a9c31cc5 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -161,39 +161,52 @@ uint64_t pc_existing_dimms_capacity(Error **errp)
     return cap.size;
 }
 
+int qmp_pc_dimm_device_info(Object *obj, PCDIMMDeviceInfo *di)
+{
+    DeviceState *dev;
+    DeviceClass *dc;
+    PCDIMMDevice *dimm;
+
+    if (!object_dynamic_cast(obj, TYPE_PC_DIMM)) {
+        return 1;
+    }
+
+    dev = DEVICE(obj);
+    dc = DEVICE_GET_CLASS(obj);
+    dimm = PC_DIMM(obj);
+
+    if (dev->id) {
+        di->has_id = true;
+        di->id = g_strdup(dev->id);
+    }
+    di->hotplugged = dev->hotplugged;
+    di->hotpluggable = dc->hotpluggable;
+    di->addr = dimm->addr;
+    di->slot = dimm->slot;
+    di->node = dimm->node;
+    di->size = object_property_get_int(OBJECT(dimm), PC_DIMM_SIZE_PROP, NULL);
+    di->memdev = object_get_canonical_path(OBJECT(dimm->hostmem));
+
+    return 0;
+}
+
 int qmp_pc_dimm_device_list(Object *obj, void *opaque)
 {
     MemoryDeviceInfoList ***prev = opaque;
+    PCDIMMDeviceInfo *di = g_new0(PCDIMMDeviceInfo, 1);
 
-    if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
-        DeviceState *dev = DEVICE(obj);
-
-        if (dev->realized) {
-            MemoryDeviceInfoList *elem = g_new0(MemoryDeviceInfoList, 1);
-            MemoryDeviceInfo *info = g_new0(MemoryDeviceInfo, 1);
-            PCDIMMDeviceInfo *di = g_new0(PCDIMMDeviceInfo, 1);
-            DeviceClass *dc = DEVICE_GET_CLASS(obj);
-            PCDIMMDevice *dimm = PC_DIMM(obj);
-
-            if (dev->id) {
-                di->has_id = true;
-                di->id = g_strdup(dev->id);
-            }
-            di->hotplugged = dev->hotplugged;
-            di->hotpluggable = dc->hotpluggable;
-            di->addr = dimm->addr;
-            di->slot = dimm->slot;
-            di->node = dimm->node;
-            di->size = object_property_get_int(OBJECT(dimm), PC_DIMM_SIZE_PROP,
-                                               NULL);
-            di->memdev = object_get_canonical_path(OBJECT(dimm->hostmem));
-
-            info->u.dimm.data = di;
-            elem->value = info;
-            elem->next = NULL;
-            **prev = elem;
-            *prev = &elem->next;
-        }
+    if (qmp_pc_dimm_device_info(obj, di)) {
+        g_free(di);
+    } else {
+        MemoryDeviceInfoList *elem = g_new0(MemoryDeviceInfoList, 1);
+        MemoryDeviceInfo *info = g_new0(MemoryDeviceInfo, 1);
+
+        info->type = MEMORY_DEVICE_TYPE_DIMM;
+        info->u.dimm.data = di;
+        elem->value = info;
+        elem->next = NULL;
+        **prev = elem;
+        *prev = &elem->next;
     }
 
     object_child_foreach(obj, qmp_pc_dimm_device_list, opaque);
diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h
index 03e1ff9558..89c79564c8 100644
--- a/include/hw/mem/nvdimm.h
+++ b/include/hw/mem/nvdimm.h
@@ -132,4 +132,6 @@ void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data,
                        uint32_t ram_slots);
 void nvdimm_plug(AcpiNVDIMMState *state);
 void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev);
+
+int qmp_nvdimm_device_list(Object *obj, void *opaque);
 #endif
diff --git a/include/hw/mem/pc-dimm.h b/include/hw/mem/pc-dimm.h
index 1e483f2670..5f74febeaa 100644
--- a/include/hw/mem/pc-dimm.h
+++ b/include/hw/mem/pc-dimm.h
@@ -93,6 +93,7 @@ uint64_t pc_dimm_get_free_addr(uint64_t address_space_start,
 
 int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp);
 
+int qmp_pc_dimm_device_info(Object *obj, PCDIMMDeviceInfo *di);
 int qmp_pc_dimm_device_list(Object *obj, void *opaque);
 uint64_t pc_existing_dimms_capacity(Error **errp);
 void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms,
diff --git a/qapi-schema.json b/qapi-schema.json
index 32b4a4b782..5280de2405 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -5811,24 +5811,62 @@
 }
 
 ##
+# @NVDIMMDeviceInfo:
+#
+# NVDIMMDevice state information
+#
+# @label-size: size the label storage area
+#
+# Since 2.9
+##
+{ 'struct': 'NVDIMMDeviceInfo',
+  'base': 'PCDIMMDeviceInfo',
+  'data': { 'label-size': 'int' }
+}
+
+##
 # @MemoryDeviceInfo:
 #
 # Union containing information about a memory device
 #
+# - @dimm: since 2.1
+# - @nvdimm: since 2.9
+#
 # Since: 2.1
 ##
-{ 'union': 'MemoryDeviceInfo', 'data': {'dimm': 'PCDIMMDeviceInfo'} }
+{ 'union': 'MemoryDeviceInfo',
+  'data': {'dimm': 'PCDIMMDeviceInfo', 'nvdimm': 'NVDIMMDeviceInfo'}
+}
+
+##
+# @MemoryDeviceType:
+#
+# Type of memory devices.
+#
+# @dimm: pc-dimm memory device
+#
+# @nvdimm: nvdimm memory device
+#
+# Since 2.9
+##
+{ 'enum': 'MemoryDeviceType', 'data': [ 'dimm', 'nvdimm' ] }
 
 ##
 # @query-memory-devices:
 #
-# Lists available memory devices and their state
+# Lists available memory devices and their state. If the optional argument
+# @devtype is present, only memory devices of the specified type are included.
+#
+# @devtype: specify the type of memory devices to be listed. If 'dimm' is
+#           specified, all pc-dimm devices (including nvdimm devices which is
+#           a subtype of pc-dimm) will be listed. If 'nvdimm' is specified,
+#           only nvdimm devices will be listed. (Since 2.9)
 #
 # Since: 2.1
 #
 # Example:
 #
-# -> { "execute": "query-memory-devices" }
+# -> { "execute": "query-memory-devices", "arguments": { "devtype": "dimm" } }
 # <- { "return": [ { "data":
 #                       { "addr": 5368709120,
 #                         "hotpluggable": true,
@@ -5842,7 +5880,9 @@
 #                  } ] }
 #
 ##
-{ 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
+{ 'command': 'query-memory-devices',
+  'data': { '*devtype': 'MemoryDeviceType' },
+  'returns': ['MemoryDeviceInfo'] }
 
 ##
 # @ACPISlotType:
diff --git a/qmp.c b/qmp.c
index fa82b598c6..179a10bced 100644
--- a/qmp.c
+++ b/qmp.c
@@ -36,6 +36,7 @@
 #include "hw/boards.h"
 #include "qom/object_interfaces.h"
 #include "hw/mem/pc-dimm.h"
+#include "hw/mem/nvdimm.h"
 #include "hw/acpi/acpi_dev_interface.h"
 
 NameInfo *qmp_query_name(Error **errp)
@@ -689,12 +690,20 @@ void qmp_object_del(const char *id, Error **errp)
     user_creatable_del(id, errp);
 }
 
-MemoryDeviceInfoList *qmp_query_memory_devices(Error **errp)
+MemoryDeviceInfoList *qmp_query_memory_devices(bool has_devtype,
+                                               MemoryDeviceType devtype,
+                                               Error **errp)
 {
     MemoryDeviceInfoList *head = NULL;
     MemoryDeviceInfoList **prev = &head;
 
-    qmp_pc_dimm_device_list(qdev_get_machine(), &prev);
+    if (!has_devtype || devtype == MEMORY_DEVICE_TYPE_DIMM) {
+        qmp_pc_dimm_device_list(qdev_get_machine(), &prev);
+    } else if (devtype == MEMORY_DEVICE_TYPE_NVDIMM) {
+        qmp_nvdimm_device_list(qdev_get_machine(), &prev);
+    } else {
+        error_setg(errp, "unrecognized memory device type %d", devtype);
+    }
 
     return head;
 }
