diff --git a/mdbx.h b/mdbx.h
index dbf622a8..e971ade5 100644
--- a/mdbx.h
+++ b/mdbx.h
@@ -5124,6 +5124,10 @@ MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *mdbx_cursor_get_userctx(const MDBX_
  * the same table handle as it was created with. This may be done whether the
  * previous transaction is live or dead.
  *
+ * If the transaction is nested, then the cursor should not be used in its parent transaction.
+ * Otherwise it is no way to restore state if this nested transaction will be aborted,
+ * nor impossible to define the expected behavior.
+ *
  * \note In contrast to LMDB, the MDBX required that any opened cursors can be
  * reused and must be freed explicitly, regardless ones was opened in a
  * read-only or write transaction. The REASON for this is eliminates ambiguity
@@ -5148,6 +5152,10 @@ LIBMDBX_API int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *cursor, MDBX_dbi db
  * the original DBI-handle internally. Thus it could be renewed with any running
  * transaction or closed.
  *
+ * If the transaction is nested, then the cursor should not be used in its parent transaction.
+ * Otherwise it is no way to restore state if this nested transaction will be aborted,
+ * nor impossible to define the expected behavior.
+ *
  * \see mdbx_cursor_renew()
  * \see mdbx_cursor_bind()
  * \see mdbx_cursor_close()
@@ -5232,6 +5240,10 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
  * Unbinds either closes all cursors associated (opened or renewed) with
  * a given transaction in a bulk with minimal overhead.
  *
+ * A transaction should not be nested, since in this case no way to restore
+ * state if this nested transaction will be aborted, nor impossible to define
+ * the expected behavior.
+ *
  * \see mdbx_cursor_unbind()
  * \see mdbx_cursor_close()
  *
@@ -5245,7 +5257,7 @@ LIBMDBX_API void mdbx_cursor_close(MDBX_cursor *cursor);
  *          some possible errors are:
  * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  *                               by current thread.
- * \retval MDBX_BAD_TXN          Given transaction is invalid or has
+ * \retval MDBX_BAD_TXN          Given transaction is invalid, nested or has
  *                               a child/nested transaction transaction. */
 LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count);
 
@@ -5255,6 +5267,10 @@ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind
  * Unbinds either closes all cursors associated (opened or renewed) with
  * a given transaction in a bulk with minimal overhead.
  *
+ * A transaction should not be nested, since in this case no way to restore
+ * state if this nested transaction will be aborted, nor impossible to define
+ * the expected behavior.
+ *
  * \see mdbx_cursor_unbind()
  * \see mdbx_cursor_close()
  *
@@ -5266,7 +5282,7 @@ LIBMDBX_API int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind
  *          some possible errors are:
  * \retval MDBX_THREAD_MISMATCH  Given transaction is not owned
  *                               by current thread.
- * \retval MDBX_BAD_TXN          Given transaction is invalid or has
+ * \retval MDBX_BAD_TXN          Given transaction is invalid, nested or has
  *                               a child/nested transaction transaction. */
 LIBMDBX_INLINE_API(int, mdbx_txn_release_all_cursors, (const MDBX_txn *txn, bool unbind)) {
   return mdbx_txn_release_all_cursors_ex(txn, unbind, NULL);
diff --git a/src/api-cursor.c b/src/api-cursor.c
index 4a4b34c8..05c98b4b 100644
--- a/src/api-cursor.c
+++ b/src/api-cursor.c
@@ -44,8 +44,10 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
   if (unlikely(!mc))
     return LOG_IFERR(MDBX_EINVAL);
 
-  if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live))
-    return LOG_IFERR(MDBX_EBADSIGN);
+  if (unlikely(mc->signature != cur_signature_ready4dispose && mc->signature != cur_signature_live)) {
+    int rc = (mc->signature == cur_signature_wait4eot) ? MDBX_EINVAL : MDBX_EBADSIGN;
+    return LOG_IFERR(rc);
+  }
 
   int rc = check_txn(txn, MDBX_TXN_BLOCKED);
   if (unlikely(rc != MDBX_SUCCESS))
@@ -58,24 +60,12 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
   if (unlikely(dbi == FREE_DBI && !(txn->flags & MDBX_TXN_RDONLY)))
     return LOG_IFERR(MDBX_EACCESS);
 
-  if (unlikely(mc->backup)) /* Cursor from parent transaction */ {
-    cASSERT(mc, mc->signature == cur_signature_live);
-    if (unlikely(cursor_dbi(mc) != dbi ||
-                 /* paranoia */ mc->signature != cur_signature_live || mc->txn != txn))
-      return LOG_IFERR(MDBX_EINVAL);
-
-    cASSERT(mc, mc->tree == &txn->dbs[dbi]);
-    cASSERT(mc, mc->clc == &txn->env->kvs[dbi].clc);
-    cASSERT(mc, cursor_dbi(mc) == dbi);
-    return likely(cursor_dbi(mc) == dbi &&
-                  /* paranoia */ mc->signature == cur_signature_live && mc->txn == txn)
-               ? MDBX_SUCCESS
-               : LOG_IFERR(MDBX_EINVAL) /* Disallow change DBI in nested
-                                           transactions */
-        ;
-  }
+  if (unlikely(mc->backup)) /* Cursor from parent transaction */
+    LOG_IFERR(MDBX_EINVAL);
 
   if (mc->signature == cur_signature_live) {
+    if (mc->txn == txn && cursor_dbi(mc) == dbi)
+      return MDBX_SUCCESS;
     rc = mdbx_cursor_unbind(mc);
     if (unlikely(rc != MDBX_SUCCESS))
       return rc;
@@ -100,25 +90,22 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) {
     return (mc->signature == cur_signature_ready4dispose) ? MDBX_SUCCESS : LOG_IFERR(MDBX_EBADSIGN);
 
   if (unlikely(mc->backup)) /* Cursor from parent transaction */
+    /* TODO: реализовать при переходе на двусвязный список курсоров */
     return LOG_IFERR(MDBX_EINVAL);
 
-  eASSERT(nullptr, mc->txn && mc->txn->signature == txn_signature);
-  cASSERT(mc, mc->signature == cur_signature_live);
-  cASSERT(mc, !mc->backup);
   if (unlikely(!mc->txn || mc->txn->signature != txn_signature)) {
     ERROR("Wrong cursor's transaction %p 0x%x", __Wpedantic_format_voidptr(mc->txn), mc->txn ? mc->txn->signature : 0);
     return LOG_IFERR(MDBX_PROBLEM);
   }
+
   if (mc->next != mc) {
-    const size_t dbi = (kvx_t *)mc->clc - mc->txn->env->kvs;
-    cASSERT(mc, cursor_dbi(mc) == dbi);
+    const size_t dbi = cursor_dbi(mc);
     cASSERT(mc, dbi < mc->txn->n_dbi);
+    cASSERT(mc, &mc->txn->env->kvs[dbi].clc == mc->clc);
     if (dbi < mc->txn->n_dbi) {
       MDBX_cursor **prev = &mc->txn->cursors[dbi];
-      while (*prev) {
+      while (/* *prev && */ *prev != mc) {
         ENSURE(mc->txn->env, (*prev)->signature == cur_signature_live || (*prev)->signature == cur_signature_wait4eot);
-        if (*prev == mc)
-          break;
         prev = &(*prev)->next;
       }
       cASSERT(mc, *prev == mc);
@@ -219,30 +206,34 @@ again:
 
 int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *count) {
   int rc = check_txn(txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD);
+  if (unlikely(rc != MDBX_SUCCESS))
+    return LOG_IFERR(rc);
+  if (unlikely(txn->parent)) {
+    rc = MDBX_BAD_TXN;
+    ERROR("%s, err %d", "must not unbind or close cursors for a nested txn", rc);
+    return rc;
+  }
+
   size_t n = 0;
-  if (likely(rc == MDBX_SUCCESS)) {
-    TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) {
-      while (txn->cursors[i]) {
-        ++n;
-        MDBX_cursor *mc = txn->cursors[i];
-        ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup);
-        txn->cursors[i] = mc->next;
-        mc->next = mc;
-        if (unbind) {
-          be_poor(mc);
-          mc->signature = cur_signature_ready4dispose;
-        } else {
-          mc->signature = 0;
-          osal_free(mc);
-        }
+  TXN_FOREACH_DBI_FROM(txn, i, MAIN_DBI) {
+    while (txn->cursors[i]) {
+      ++n;
+      MDBX_cursor *mc = txn->cursors[i];
+      ENSURE(nullptr, mc->signature == cur_signature_live && (mc->next != mc) && !mc->backup);
+      txn->cursors[i] = mc->next;
+      mc->next = mc;
+      if (unbind) {
+        be_poor(mc);
+        mc->signature = cur_signature_ready4dispose;
+      } else {
+        mc->signature = 0;
+        osal_free(mc);
       }
     }
-  } else {
-    LOG_IFERR(rc);
   }
   if (count)
     *count = n;
-  return rc;
+  return MDBX_SUCCESS;
 }
 
 int mdbx_cursor_compare(const MDBX_cursor *l, const MDBX_cursor *r, bool ignore_multival) {