diff --git a/qapi/block-export.json b/qapi/block-export.json
index ce33fe378df..b485b380f1a 100644
--- a/qapi/block-export.json
+++ b/qapi/block-export.json
@@ -30,13 +30,18 @@
 #     server from advertising multiple client support (since 5.2;
 #     default: 100)
 #
+# @handshake-limit: Time limit, in seconds, at which a client that
+#     has not completed the negotiation handshake will be disconnected,
+#     or 0 for no limit (since 9.1; default: 10).
+#
 # Since: 4.2
 ##
 { 'struct': 'NbdServerOptions',
   'data': { 'addr': 'SocketAddress',
             '*tls-creds': 'str',
             '*tls-authz': 'str',
-            '*max-connections': 'uint32' } }
+            '*max-connections': 'uint32',
+            '*handshake-limit': 'uint32' } }

 ##
 # @nbd-server-start:
@@ -65,6 +70,10 @@
 #     server from advertising multiple client support (since 5.2;
 #     default: 100).
 #
+# @handshake-limit: Time limit, in seconds, at which a client that
+#     has not completed the negotiation handshake will be disconnected,
+#     or 0 for no limit (since 9.1; default: 10).
+#
 # Errors:
 #     - if the server is already running
 #
@@ -74,7 +83,8 @@
   'data': { 'addr': 'SocketAddressLegacy',
             '*tls-creds': 'str',
             '*tls-authz': 'str',
-            '*max-connections': 'uint32' },
+            '*max-connections': 'uint32',
+            '*handshake-limit': 'uint32' },
   'allow-preconfig': true }

 ##
diff --git a/include/block/nbd.h b/include/block/nbd.h
index fd5044359dc..22071aea797 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -430,7 +430,7 @@ bool nbd_server_is_running(void);
 int nbd_server_max_connections(void);
 void nbd_server_start(SocketAddress *addr, const char *tls_creds,
                       const char *tls_authz, uint32_t max_connections,
-                      Error **errp);
+                      uint32_t handshake_limit, Error **errp);
 void nbd_server_start_options(NbdServerOptions *arg, Error **errp);

 /* nbd_read
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index bdf2eb50b68..a258e029f78 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -403,7 +403,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
     }

     nbd_server_start(addr, NULL, NULL, NBD_DEFAULT_MAX_CONNECTIONS,
-                     &local_err);
+                     NBD_DEFAULT_HANDSHAKE_LIMIT, &local_err);
     qapi_free_SocketAddress(addr);
     if (local_err != NULL) {
         goto exit;
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index 4e38ff46747..ad21bd1412d 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -30,6 +30,7 @@ typedef struct NBDServerData {
     QIONetListener *listener;
     QCryptoTLSCreds *tlscreds;
     char *tlsauthz;
+    uint32_t handshake_limit;
     uint32_t max_connections;
     uint32_t connections;
     QLIST_HEAD(, NBDConn) conns;
@@ -84,8 +85,7 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
     nbd_update_server_watch(nbd_server);

     qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
-    /* TODO - expose handshake limit as QMP option */
-    nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_LIMIT,
+    nbd_client_new(cioc, nbd_server->handshake_limit,
                    nbd_server->tlscreds, nbd_server->tlsauthz,
                    nbd_blockdev_client_closed, conn);
 }
@@ -160,7 +160,7 @@ static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)

 void nbd_server_start(SocketAddress *addr, const char *tls_creds,
                       const char *tls_authz, uint32_t max_connections,
-                      Error **errp)
+                      uint32_t handshake_limit, Error **errp)
 {
     if (nbd_server) {
         error_setg(errp, "NBD server already running");
@@ -169,6 +169,7 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,

     nbd_server = g_new0(NBDServerData, 1);
     nbd_server->max_connections = max_connections;
+    nbd_server->handshake_limit = handshake_limit;
     nbd_server->listener = qio_net_listener_new();

     qio_net_listener_set_name(nbd_server->listener,
@@ -206,15 +207,19 @@ void nbd_server_start_options(NbdServerOptions *arg, Error **errp)
     if (!arg->has_max_connections) {
         arg->max_connections = NBD_DEFAULT_MAX_CONNECTIONS;
     }
+    if (!arg->has_handshake_limit) {
+        arg->handshake_limit = NBD_DEFAULT_HANDSHAKE_LIMIT;
+    }

     nbd_server_start(arg->addr, arg->tls_creds, arg->tls_authz,
-                     arg->max_connections, errp);
+                     arg->max_connections, arg->handshake_limit, errp);
 }

 void qmp_nbd_server_start(SocketAddressLegacy *addr,
                           const char *tls_creds,
                           const char *tls_authz,
                           bool has_max_connections, uint32_t max_connections,
+                          bool has_handshake_limit, uint32_t handshake_limit,
                           Error **errp)
 {
     SocketAddress *addr_flat = socket_address_flatten(addr);
@@ -222,8 +227,12 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr,
     if (!has_max_connections) {
         max_connections = NBD_DEFAULT_MAX_CONNECTIONS;
     }
+    if (!has_handshake_limit) {
+        handshake_limit = NBD_DEFAULT_HANDSHAKE_LIMIT;
+    }

-    nbd_server_start(addr_flat, tls_creds, tls_authz, max_connections, errp);
+    nbd_server_start(addr_flat, tls_creds, tls_authz, max_connections,
+                     handshake_limit, errp);
     qapi_free_SocketAddress(addr_flat);
 }

