diff --git a/CHANGES b/CHANGES
index 77ae8add110ea274b4e83f62a0a4f058249ca211..f254f9b96072afb9814c51c6366cae9436e069c2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -29,6 +29,7 @@ OpenLDAP 2.4.12 Release (2008/10/08)
 	Fixed slapd syncrepl runqueue interval (ITS#5719)
 	Fixed slapd-bdb entry return if attr not present (ITS#5650)
 	Fixed slapd-bdb olcDbMode syntax (ITS#5713)
+	Fixed slapd-bdb entry release prior to network read (ITS#5728)
 	Fixed slapd-dnssrv memory handling (ITS#5691)
 	Fixed slapd-ldap,slapd-meta invalid filter behavior (ITS#5614)
 	Fixed slapd-meta memory handling (ITS#5691)
diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h
index 3fa4053adfccd57d5cef2836babf70af7f4fae32..19c30cc5e110f6ce7864c325b84b6861fb5ee4ae 100644
--- a/servers/slapd/back-bdb/back-bdb.h
+++ b/servers/slapd/back-bdb/back-bdb.h
@@ -238,17 +238,21 @@ struct bdb_info {
 
 struct bdb_lock_info {
 	struct bdb_lock_info *bli_next;
-	ID		bli_id;
 	DB_LOCK	bli_lock;
+	ID		bli_id;
+	int		bli_flag;
 };
+#define	BLI_DONTFREE	1
 
 struct bdb_op_info {
 	OpExtra boi_oe;
 	DB_TXN*		boi_txn;
-	u_int32_t	boi_err;
-	int		boi_acl_cache;
 	struct bdb_lock_info *boi_locks;	/* used when no txn */
+	u_int32_t	boi_err;
+	char		boi_acl_cache;
+	char		boi_flag;
 };
+#define BOI_DONTFREE	1
 
 #define	DB_OPEN(db, file, name, type, flags, mode) \
 	((db)->open)(db, file, name, type, flags, mode)
diff --git a/servers/slapd/back-bdb/id2entry.c b/servers/slapd/back-bdb/id2entry.c
index 79c6f88a23fedc6e15a14004334dbb5f7a9220ae..d585bfdcd55c8a2341575bc36a40685bf563a95e 100644
--- a/servers/slapd/back-bdb/id2entry.c
+++ b/servers/slapd/back-bdb/id2entry.c
@@ -267,13 +267,18 @@ int bdb_entry_release(
 				if ( bli->bli_id == e->e_id ) {
 					bdb_cache_return_entry_rw( bdb, e, rw, &bli->bli_lock );
 					prev->bli_next = bli->bli_next;
-					op->o_tmpfree( bli, op->o_tmpmemctx );
+					/* Cleanup, or let caller know we unlocked */
+					if ( bli->bli_flag & BLI_DONTFREE )
+						bli->bli_flag = 0;
+					else
+						op->o_tmpfree( bli, op->o_tmpmemctx );
 					break;
 				}
 			}
 			if ( !boi->boi_locks ) {
 				LDAP_SLIST_REMOVE( &op->o_extra, &boi->boi_oe, OpExtra, oe_next );
-				op->o_tmpfree( boi, op->o_tmpmemctx );
+				if ( !(boi->boi_flag & BOI_DONTFREE))
+					op->o_tmpfree( boi, op->o_tmpmemctx );
 			}
 		}
 	} else {
diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c
index 646493948c9a42e91db66be2d9a7093266689cf5..bbff1f4ebe3afaa746e5a743a734ae030e666d09 100644
--- a/servers/slapd/back-bdb/search.c
+++ b/servers/slapd/back-bdb/search.c
@@ -857,6 +857,13 @@ fetch_entry_retry:
 				op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL
 					? LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );
 
+			/* free reader lock */
+#ifdef SLAP_ZONE_ALLOC
+			slap_zn_runlock(bdb->bi_cache.c_zctx, e);
+#endif
+			bdb_cache_return_entry_r( bdb, e, &lock );
+			e = NULL;
+
 			send_search_reference( op, rs );
 
 			ber_bvarray_free( rs->sr_ref );
@@ -889,14 +896,55 @@ fetch_entry_retry:
 			}
 
 			if (e) {
+				struct bdb_op_info bois;
+				struct bdb_lock_info blis;
+
+				/* Must set lockinfo so that entry_release will work */
+				if (!opinfo) {
+					bois.boi_oe.oe_key = bdb;
+					bois.boi_txn = NULL;
+					bois.boi_err = 0;
+					bois.boi_acl_cache = op->o_do_not_cache;
+					bois.boi_flag = BOI_DONTFREE;
+					bois.boi_locks = &blis;
+					blis.bli_next = NULL;
+					LDAP_SLIST_INSERT_HEAD( &op->o_extra, &bois.boi_oe,
+						oe_next );
+				} else {
+					blis.bli_next = opinfo->boi_locks;
+					opinfo->boi_locks = &blis;
+				}
+				blis.bli_id = e->e_id;
+				blis.bli_lock = lock;
+				blis.bli_flag = BLI_DONTFREE;
+
 				/* safe default */
 				rs->sr_attrs = op->oq_search.rs_attrs;
 				rs->sr_operational_attrs = NULL;
 				rs->sr_ctrls = NULL;
-				rs->sr_flags = 0;
+				rs->sr_flags = REP_ENTRY_MUSTRELEASE;
 				rs->sr_err = LDAP_SUCCESS;
 				rs->sr_err = send_search_entry( op, rs );
 
+				/* send_search_entry will usually free it.
+				 * an overlay might leave its own copy here;
+				 * bli_flag will be 0 if lock was already released.
+				 */
+				if ( blis.bli_flag ) {
+#ifdef SLAP_ZONE_ALLOC
+					slap_zn_runlock(bdb->bi_cache.c_zctx, e);
+#endif
+					bdb_cache_return_entry_r(bdb, e, &lock);
+					if ( opinfo ) {
+						opinfo->boi_locks = blis.bli_next;
+					} else {
+						LDAP_SLIST_REMOVE( &op->o_extra, &bois.boi_oe,
+							OpExtra, oe_next );
+					}
+				}
+				rs->sr_entry = NULL;
+				e = NULL;
+
 				switch ( rs->sr_err ) {
 				case LDAP_SUCCESS:	/* entry sent ok */
 					break;
@@ -904,12 +952,6 @@ fetch_entry_retry:
 					break;
 				case LDAP_UNAVAILABLE:
 				case LDAP_SIZELIMIT_EXCEEDED:
-#ifdef SLAP_ZONE_ALLOC
-					slap_zn_runlock(bdb->bi_cache.c_zctx, e);
-#endif
-					bdb_cache_return_entry_r(bdb, e, &lock);
-					e = NULL;
-					rs->sr_entry = NULL;
 					if ( rs->sr_err == LDAP_SIZELIMIT_EXCEEDED ) {
 						rs->sr_ref = rs->sr_v2ref;
 						send_ldap_result( op, rs );