diff --git a/servers/slapd/back-mdb/dn2id.c b/servers/slapd/back-mdb/dn2id.c
index 5431226ae43b26bce9c7b403a0fae74c6f5408c5..45a36e28048d8e24b44f1cda3732759cd854a0d6 100644
--- a/servers/slapd/back-mdb/dn2id.c
+++ b/servers/slapd/back-mdb/dn2id.c
@@ -136,14 +136,13 @@ int mdb_fix_dn(
 int
 mdb_dn2id_add(
 	Operation	*op,
-	MDB_txn *txn,
+	MDB_cursor	*mcp,
+	MDB_cursor	*mcd,
 	ID pid,
 	Entry		*e )
 {
 	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
-	MDB_dbi dbi = mdb->mi_dn2id;
 	MDB_val		key, data;
-	MDB_cursor	*mc;
 	ID		nid;
 	int		rc, rlen, nrlen;
 	diskNode *d;
@@ -174,10 +173,6 @@ mdb_dn2id_add(
 
 	nid = pid;
 
-	rc = mdb_cursor_open( txn, dbi, &mc );
-	if ( rc )
-		goto fail;
-
 	/* Need to make dummy root node once. Subsequent attempts
 	 * will fail harmlessly.
 	 */
@@ -186,22 +181,21 @@ mdb_dn2id_add(
 		data.mv_data = &dummy;
 		data.mv_size = sizeof(diskNode);
 
-		mdb_cursor_put( mc, &key, &data, MDB_NODUPDATA );
+		mdb_cursor_put( mcp, &key, &data, MDB_NODUPDATA );
 	}
 
 	data.mv_data = d;
 	data.mv_size = sizeof(diskNode) + rlen + nrlen;
 
-	rc = mdb_cursor_put( mc, &key, &data, MDB_NODUPDATA );
+	rc = mdb_cursor_put( mcp, &key, &data, MDB_NODUPDATA );
 
 	if (rc == 0) {
 		nid = e->e_id;
 		memcpy( ptr, &pid, sizeof( ID ));
 		d->nrdnlen[0] ^= 0x80;
 
-		rc = mdb_cursor_put( mc, &key, &data, MDB_NODUPDATA|MDB_APPEND );
+		rc = mdb_cursor_put( mcd, &key, &data, MDB_NODUPDATA|MDB_APPEND );
 	}
-	mdb_cursor_close( mc );
 
 fail:
 	op->o_tmpfree( d, op->o_tmpmemctx );
@@ -210,61 +204,47 @@ fail:
 	return rc;
 }
 
+/* mc must have been set by mdb_dn2id */
 int
 mdb_dn2id_delete(
 	Operation	*op,
-	MDB_txn *txn,
-	ID pid,
-	Entry	*e )
+	MDB_cursor *mc,
+	ID id )
 {
-	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
-	MDB_dbi dbi = mdb->mi_dn2id;
-	MDB_val	key, data;
-	diskNode *d;
-	int rc, nrlen;
-	ID	nid;
-
-	Debug( LDAP_DEBUG_TRACE, "=> mdb_dn2id_delete 0x%lx: \"%s\"\n",
-		e->e_id, e->e_ndn, 0 );
-
-	key.mv_size = sizeof(ID);
-	key.mv_data = &nid;
-	nid = pid;
-
-	nrlen = dn_rdnlen( op->o_bd, &e->e_nname );
-	data.mv_size = sizeof(diskNode) + nrlen - sizeof(ID) - 1;
+	int rc;
 
-	d = op->o_tmpalloc( data.mv_size, op->o_tmpmemctx );
-	d->nrdnlen[1] = nrlen & 0xff;
-	d->nrdnlen[0] = (nrlen >> 8) | 0x80;
-	memcpy( d->nrdn, e->e_nname.bv_val, nrlen );
-	d->nrdn[nrlen] = '\0';
-	data.mv_data = d;
+	Debug( LDAP_DEBUG_TRACE, "=> mdb_dn2id_delete 0x%lx\n",
+		id, 0, 0 );
 
 	/* Delete our ID from the parent's list */
-	rc = mdb_del( txn, dbi, &key, &data );
+	rc = mdb_cursor_del( mc, 0 );
 
 	/* Delete our ID from the tree. With sorted duplicates, this
 	 * will leave any child nodes still hanging around. This is OK
 	 * for modrdn, which will add our info back in later.
 	 */
 	if ( rc == 0 ) {
-		nid = e->e_id;
-		d->nrdnlen[0] ^= 0x80;
-		rc = mdb_del( txn, dbi, &key, &data );
+		MDB_val	key;
+		key.mv_size = sizeof(ID);
+		key.mv_data = &id;
+		rc = mdb_cursor_get( mc, &key, NULL, MDB_SET );
+		if ( rc == 0 )
+			rc = mdb_cursor_del( mc, 0 );
 	}
 
-	op->o_tmpfree( d, op->o_tmpmemctx );
-
-	Debug( LDAP_DEBUG_TRACE, "<= mdb_dn2id_delete 0x%lx: %d\n", e->e_id, rc, 0 );
+	Debug( LDAP_DEBUG_TRACE, "<= mdb_dn2id_delete 0x%lx: %d\n", id, rc, 0 );
 	return rc;
 }
 
-/* return last found ID in *id if no match */
+/* return last found ID in *id if no match
+ * If mc is provided, it will be left pointing to the RDN's
+ * record under the parent's ID.
+ */
 int
 mdb_dn2id(
 	Operation	*op,
 	MDB_txn *txn,
+	MDB_cursor	*mc,
 	struct berval	*in,
 	ID	*id,
 	struct berval	*matched,
@@ -316,8 +296,12 @@ mdb_dn2id(
 	nid = 0;
 	key.mv_size = sizeof(ID);
 
-	rc = mdb_cursor_open( txn, dbi, &cursor );
-	if ( rc ) return rc;
+	if ( mc ) {
+		cursor = mc;
+	} else {
+		rc = mdb_cursor_open( txn, dbi, &cursor );
+		if ( rc ) return rc;
+	}
 
 	for (;;) {
 		key.mv_data = &pid;
@@ -367,7 +351,8 @@ mdb_dn2id(
 		}
 	}
 	*id = nid; 
-	mdb_cursor_close( cursor );
+	if ( !mc )
+		mdb_cursor_close( cursor );
 done:
 	if ( matched ) {
 		if ( matched->bv_len ) {
diff --git a/servers/slapd/back-mdb/id2entry.c b/servers/slapd/back-mdb/id2entry.c
index afa7539fdda503ea60731c501472d8298fb55c22..d2f1715477feebb58ad161afec0bd55b6934f7c2 100644
--- a/servers/slapd/back-mdb/id2entry.c
+++ b/servers/slapd/back-mdb/id2entry.c
@@ -31,18 +31,18 @@ typedef struct Ecount {
 
 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
 	Ecount *eh);
-static int mdb_entry_encode(Operation *op, MDB_txn *txn, Entry *e, MDB_val *data,
+static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data,
 	Ecount *ec);
 static Entry *mdb_entry_alloc( Operation *op, int nattrs, int nvals );
 
 static int mdb_id2entry_put(
 	Operation *op,
-	MDB_txn *tid,
+	MDB_txn *txn,
+	MDB_cursor *mc,
 	Entry *e,
 	int flag )
 {
 	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
-	MDB_dbi dbi = mdb->mi_id2entry;
 	Ecount ec;
 	MDB_val key, data;
 	int rc;
@@ -52,7 +52,7 @@ static int mdb_id2entry_put(
 	key.mv_data = &e->e_id;
 	key.mv_size = sizeof(ID);
 
-	rc = mdb_entry_partsize( mdb, tid, e, &ec );
+	rc = mdb_entry_partsize( mdb, txn, e, &ec );
 	if (rc)
 		return LDAP_OTHER;
 
@@ -60,9 +60,12 @@ static int mdb_id2entry_put(
 
 again:
 	data.mv_size = ec.len;
-	rc = mdb_put( tid, dbi, &key, &data, flag );
+	if ( mc )
+		rc = mdb_cursor_put( mc, &key, &data, flag );
+	else
+		rc = mdb_put( txn, mdb->mi_id2entry, &key, &data, flag );
 	if (rc == MDB_SUCCESS) {
-		rc = mdb_entry_encode( op, tid, e, &data, &ec );
+		rc = mdb_entry_encode( op, e, &data, &ec );
 		if( rc != LDAP_SUCCESS )
 			return LDAP_OTHER;
 	}
@@ -76,7 +79,8 @@ again:
 			"mdb_id2entry_put: mdb_put failed: %s(%d) \"%s\"\n",
 			mdb_strerror(rc), rc,
 			e->e_nname.bv_val );
-		rc = LDAP_OTHER;
+		if ( rc != MDB_KEYEXIST )
+			rc = LDAP_OTHER;
 	}
 	return rc;
 }
@@ -89,18 +93,20 @@ again:
 
 int mdb_id2entry_add(
 	Operation *op,
-	MDB_txn *tid,
+	MDB_txn *txn,
+	MDB_cursor *mc,
 	Entry *e )
 {
-	return mdb_id2entry_put(op, tid, e, MDB_NOOVERWRITE|MDB_APPEND);
+	return mdb_id2entry_put(op, txn, mc, e, MDB_NOOVERWRITE|MDB_APPEND);
 }
 
 int mdb_id2entry_update(
 	Operation *op,
-	MDB_txn *tid,
+	MDB_txn *txn,
+	MDB_cursor *mc,
 	Entry *e )
 {
-	return mdb_id2entry_put(op, tid, e, 0);
+	return mdb_id2entry_put(op, txn, mc, e, 0);
 }
 
 int mdb_id2entry(
@@ -289,7 +295,7 @@ int mdb_entry_get(
 	txn = moi->moi_txn;
 
 	/* can we find entry */
-	rc = mdb_dn2entry( op, txn, ndn, &e, 0 );
+	rc = mdb_dn2entry( op, txn, NULL, ndn, &e, 0 );
 	switch( rc ) {
 	case MDB_NOTFOUND:
 	case 0:
@@ -537,7 +543,7 @@ static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
  * The entire buffer size is precomputed so that a single malloc can be
  * performed.
  */
-static int mdb_entry_encode(Operation *op, MDB_txn *txn, Entry *e, MDB_val *data, Ecount *eh)
+static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *eh)
 {
 	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
 	ber_len_t len, i;
diff --git a/servers/slapd/back-mdb/nextid.c b/servers/slapd/back-mdb/nextid.c
index 1d7b3893cb0d3c431154a5cea08cb866ee943eb4..d6c5d945765ff5b31c7a7c067d7d494caa8e5ff6 100644
--- a/servers/slapd/back-mdb/nextid.c
+++ b/servers/slapd/back-mdb/nextid.c
@@ -21,21 +21,13 @@
 
 #include "back-mdb.h"
 
-int mdb_next_id( BackendDB *be, MDB_txn *tid, ID *out )
+int mdb_next_id( BackendDB *be, MDB_cursor *mc, ID *out )
 {
-	struct mdb_info *mdb = (struct mdb_info *) be->be_private;
 	int rc;
 	ID id = 0;
 	MDB_val key;
-	MDB_cursor *cursor;
 
-	/* Get a read cursor */
-	rc = mdb_cursor_open( tid, mdb->mi_id2entry, &cursor );
-
-	if (rc == 0) {
-		rc = mdb_cursor_get(cursor, &key, NULL, MDB_LAST);
-		mdb_cursor_close(cursor);
-	}
+	rc = mdb_cursor_get(mc, &key, NULL, MDB_LAST);
 
 	switch(rc) {
 	case MDB_NOTFOUND: