diff --git a/include/block/nbd.h b/include/block/nbd.h
index 78d101b774..3d379b5539 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -157,6 +157,10 @@ enum {
 #define NBD_FLAG_SEND_RESIZE       (1 << NBD_FLAG_SEND_RESIZE_BIT)
 #define NBD_FLAG_SEND_CACHE        (1 << NBD_FLAG_SEND_CACHE_BIT)
 #define NBD_FLAG_SEND_FAST_ZERO    (1 << NBD_FLAG_SEND_FAST_ZERO_BIT)
+/*
+ * If you add any new NBD_FLAG_ flag, check that logic in
+ * nbd_is_new_info_compatible() is still good about handling flags.
+ */
 
 /* New-style handshake (global) flags, sent from server to client, and
    control what will happen during handshake phase. */
@@ -305,6 +309,11 @@ struct NBDExportInfo {
 
     uint32_t context_id;
 
+    /*
+     * WARNING! when add any new field to the structure, don't forget to check
+     * and updated nbd_is_new_info_compatible() function.
+     */
+
     /* Set by server results during nbd_receive_export_list() */
     char *description;
     int n_contexts;
diff --git a/nbd/client-connection.c b/nbd/client-connection.c
index 695f855754..2d66993632 100644
--- a/nbd/client-connection.c
+++ b/nbd/client-connection.c
@@ -37,6 +37,10 @@ struct NBDClientConnection {
     bool do_negotiation;
     bool do_retry;
 
+    /* Used only by connection thread, no need in locking the mutex */
+    bool has_prev_info;
+    NBDExportInfo prev_info;
+
     QemuMutex mutex;
 
     /*
@@ -160,6 +164,67 @@ static int nbd_connect(QIOChannelSocket *sioc, SocketAddress *addr,
     return 0;
 }
 
+static bool nbd_is_new_info_compatible(NBDExportInfo *old, NBDExportInfo *new,
+                                       Error **errp)
+{
+    uint32_t dropped_flags;
+
+    if (old->structured_reply && !new->structured_reply) {
+        error_setg(errp, "Server options degrade after reconnect: "
+                   "structured_reply is not supported anymore");
+        return false;
+    }
+
+    if (old->base_allocation && !new->base_allocation) {
+        error_setg(errp, "Server options degrade after reconnect: "
+                   "base_allocation is not supported anymore");
+        return false;
+    }
+
+    if (old->size != new->size) {
+        error_setg(errp, "NBD export size changed after reconnect");
+        return false;
+    }
+
+    /*
+     * No worry if rotational status changed. But other flags are feature flags,
+     * they should not degrade.
+     */
+    dropped_flags = (old->flags & ~new->flags) & ~NBD_FLAG_ROTATIONAL;
+    if (dropped_flags) {
+        error_setg(errp, "Server options degrade after reconnect: flags 0x%"
+                   PRIx32 " are not reported anymore", dropped_flags);
+        return false;
+    }
+
+    if (new->min_block > old->min_block) {
+        error_setg(errp, "Server requires more strict min_block after "
+                   "reconnect: %" PRIu32 " instead of %" PRIu32,
+                   new->min_block, old->min_block);
+        return false;
+    }
+    if (new->min_block && (old->min_block % new->min_block)) {
+        error_setg(errp, "Server requires new min_block %" PRIu32
+                   " after reconnect, incompatible with old one %" PRIu32,
+                   new->min_block, old->min_block);
+        return false;
+    }
+
+    if (new->max_block < old->max_block) {
+        error_setg(errp, "Server requires more strict max_block after "
+                   "reconnect: %" PRIu32 " instead of %" PRIu32,
+                   new->max_block, old->max_block);
+        return false;
+    }
+
+    if (old->context_id != new->context_id) {
+        error_setg(errp, "Meta context id changed after reconnect");
+        return false;
+    }
+
+    return true;
+}
+
 static void *connect_thread_func(void *opaque)
 {
     NBDClientConnection *conn = opaque;
@@ -183,6 +248,27 @@ static void *connect_thread_func(void *opaque)
                           conn->do_negotiation ? &conn->updated_info : NULL,
                           conn->tlscreds, &conn->ioc, &conn->err);
 
+        if (ret == 0) {
+            if (conn->has_prev_info &&
+                !nbd_is_new_info_compatible(&conn->prev_info,
+                                            &conn->updated_info, &conn->err))
+            {
+                NBDRequest request = { .type = NBD_CMD_DISC };
+                QIOChannel *ioc = conn->ioc ?: QIO_CHANNEL(conn->sioc);
+
+                nbd_send_request(ioc, &request);
+                qio_channel_close(ioc, NULL);
+
+                object_unref(OBJECT(conn->ioc));
+                conn->ioc = NULL;
+
+                ret = -EINVAL;
+            } else {
+                conn->prev_info = conn->updated_info;
+                conn->has_prev_info = true;
+            }
+        }
+
         /*
          * conn->updated_info will finally be returned to the user. Clear the
          * pointers to our internally allocated strings, which are IN parameters
