diff --git a/hmp-commands.hx b/hmp-commands.hx
index 18cb415..9cd5ed1 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1240,6 +1240,23 @@ used by another monitor command.
 ETEXI
 
     {
+        .name       = "getfd_file",
+        .args_type  = "filename:s",
+        .params     = "getfd_file filename",
+        .help       = "receive a file descriptor via SCM rights and assign it a filename",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_getfd_file,
+    },
+
+STEXI
+@item getfd_file @var{filename}
+@findex getfd_file
+If a file descriptor is passed alongside this command using the SCM_RIGHTS
+mechanism on unix sockets, it is stored using the name @var{filename} for
+later use by other monitor commands.
+ETEXI
+
+    {
         .name       = "block_passwd",
         .args_type  = "device:B,password:s",
         .params     = "block_passwd device password",
diff --git a/monitor.c b/monitor.c
index 12a6fe2..bdf4dd8 100644
--- a/monitor.c
+++ b/monitor.c
@@ -163,6 +163,7 @@ struct Monitor {
 #endif
     QError *error;
     QLIST_HEAD(,mon_fd_t) fds;
+    QLIST_HEAD(,mon_fd_t) file_fds;
     QLIST_ENTRY(Monitor) entry;
 };
 
@@ -2256,6 +2257,42 @@ static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
     return -1;
 }
 
+static int do_getfd_file(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    const char *filename = qdict_get_str(qdict, "filename");
+    mon_fd_t *monfd;
+    int fd;
+
+    fd = qemu_chr_fe_get_msgfd(mon->chr);
+    if (fd == -1) {
+        qerror_report(QERR_FD_NOT_SUPPLIED);
+        return -1;
+    }
+
+    if (qemu_isdigit(filename[0])) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "filename",
+                      "a name not starting with a digit");
+        return -1;
+    }
+
+    QLIST_FOREACH(monfd, &mon->file_fds, next) {
+        if (strcmp(monfd->name, filename) != 0) {
+            continue;
+        }
+
+        close(monfd->fd);
+        monfd->fd = fd;
+        return 0;
+    }
+
+    monfd = g_malloc0(sizeof(mon_fd_t));
+    monfd->name = g_strdup(filename);
+    monfd->fd = fd;
+
+    QLIST_INSERT_HEAD(&mon->file_fds, monfd, next);
+    return 0;
+}
+
 static void do_loadvm(Monitor *mon, const QDict *qdict)
 {
     int saved_vm_running  = runstate_is_running();
@@ -2292,6 +2329,39 @@ int monitor_get_fd(Monitor *mon, const char *fdname)
     return -1;
 }
 
+int monitor_get_fd_file(Monitor *mon, const char *filename,
+                        bool take_ownership)
+{
+    mon_fd_t *monfd;
+
+    QLIST_FOREACH(monfd, &mon->file_fds, next) {
+        int fd;
+
+        if (strcmp(monfd->name, filename) != 0) {
+            continue;
+        }
+
+        fd = monfd->fd;
+
+        if (take_ownership) {
+            /* caller takes ownership of fd */
+            QLIST_REMOVE(monfd, next);
+            g_free(monfd->name);
+            g_free(monfd);
+        }
+
+        return fd;
+    }
+
+    return -1;
+}
+
+int qemu_get_fd_file(const char *filename, bool take_ownership)
+{
+    return cur_mon ?
+           monitor_get_fd_file(cur_mon, filename, take_ownership) : -1;
+}
+
 /* mon_cmds and info_cmds would be sorted at runtime */
 static mon_cmd_t mon_cmds[] = {
 #include "hmp-commands.h"
diff --git a/monitor.h b/monitor.h
index 0d49800..529d8a7 100644
--- a/monitor.h
+++ b/monitor.h
@@ -60,6 +60,9 @@ int monitor_read_block_device_key(Monitor *mon, const char *device,
                                   void *opaque);
 
 int monitor_get_fd(Monitor *mon, const char *fdname);
+int monitor_get_fd_file(Monitor *mon, const char *filename,
+                        bool take_ownership);
+int qemu_get_fd_file(const char *filename, bool take_ownership);
 
 void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
     GCC_FMT_ATTR(2, 0);
diff --git a/qemu-tool.c b/qemu-tool.c
index 07fc4f2..d3d86bf 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -111,3 +111,8 @@ void migrate_add_blocker(Error *reason)
 void migrate_del_blocker(Error *reason)
 {
 }
+
+int qemu_get_fd_file(const char *fdname, bool take_ownership)
+{
+    return -1;
+}
diff --git a/qmp-commands.hx b/qmp-commands.hx
index db980fa..1825a91 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -891,6 +891,36 @@ Example:
 EQMP
 
     {
+        .name       = "getfd_file",
+        .args_type  = "filename:s",
+        .params     = "getfd_file filename",
+        .help       = "receive a file descriptor via SCM rights and assign it a filename",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_getfd_file,
+    },
+
+
+SQMP
+
+getfd_file
+--------------
+
+Receive a file descriptor via SCM rights and assign it a filename.
+
+Arguments:
+
+- "filename": filename (json-string)
+
+Example:
+
+-> { "execute": "getfd_file",
+                "arguments": { "filename": "/var/lib/libvirt/images/tst.img" } }
+<- { "return": {} }
+
+
+EQMP
+
+    {
         .name       = "block_passwd",
         .args_type  = "device:B,password:s",
         .mhandler.cmd_new = qmp_marshal_input_block_passwd,
