diff --git a/CHANGES b/CHANGES
index 2bb9ca2e25d358b0394a601ac05ed74fff1229d1..22caa824763e3ff9ede86a51aa8f6faa74bb9ae7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -11,6 +11,8 @@ OpenLDAP 2.4.14 Engineering
 	Added slapo-rwm newRDN rewriting (ITS#5834)
 	Fixed slapd bconfig to return error codes (ITS#5867)
 	Fixed slapd bconfig encoding incorrectly (ITS#5897)
+	Fixed slapd connection assert (ITS#5835)
+	Fixed slapd epoll handling (ITS#5886)
 	Fixed slapd syncrepl rename handling (ITS#5809)
 	Fixed slapd syncrepl MMR when adding new server (ITS#5850)
 	Fixed slapd syncrepl replication with glued DB (ITS#5866)
diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c
index 4c3178e338c74a58b00cc00beabccb38e8f3259d..7c40df58584347e6ccef8207743785f25db82a35 100644
--- a/servers/slapd/connection.c
+++ b/servers/slapd/connection.c
@@ -163,8 +163,10 @@ int connections_destroy(void)
 		if( connections[i].c_struct_state != SLAP_C_UNINITIALIZED ) {
 			ber_sockbuf_free( connections[i].c_sb );
 			ldap_pvt_thread_mutex_destroy( &connections[i].c_mutex );
-			ldap_pvt_thread_mutex_destroy( &connections[i].c_write_mutex );
-			ldap_pvt_thread_cond_destroy( &connections[i].c_write_cv );
+			ldap_pvt_thread_mutex_destroy( &connections[i].c_write1_mutex );
+			ldap_pvt_thread_mutex_destroy( &connections[i].c_write2_mutex );
+			ldap_pvt_thread_cond_destroy( &connections[i].c_write1_cv );
+			ldap_pvt_thread_cond_destroy( &connections[i].c_write2_cv );
 #ifdef LDAP_SLAPI
 			if ( slapi_plugins_used ) {
 				slapi_int_free_object_extensions( SLAPI_X_EXT_CONNECTION,
@@ -384,8 +386,10 @@ Connection * connection_init(
 
 		/* should check status of thread calls */
 		ldap_pvt_thread_mutex_init( &c->c_mutex );
-		ldap_pvt_thread_mutex_init( &c->c_write_mutex );
-		ldap_pvt_thread_cond_init( &c->c_write_cv );
+		ldap_pvt_thread_mutex_init( &c->c_write1_mutex );
+		ldap_pvt_thread_mutex_init( &c->c_write2_mutex );
+		ldap_pvt_thread_cond_init( &c->c_write1_cv );
+		ldap_pvt_thread_cond_init( &c->c_write2_cv );
 
 #ifdef LDAP_SLAPI
 		if ( slapi_plugins_used ) {
@@ -417,6 +421,7 @@ Connection * connection_init(
 	assert( c->c_sasl_bindop == NULL );
 	assert( c->c_currentber == NULL );
 	assert( c->c_writewaiter == 0);
+	assert( c->c_writers == 0);
 
 	c->c_listener = listener;
 	c->c_sd = s;
@@ -593,6 +598,7 @@ connection_destroy( Connection *c )
 	assert( LDAP_STAILQ_EMPTY(&c->c_txn_ops) );
 #endif
 	assert( c->c_writewaiter == 0);
+	assert( c->c_writers == 0);
 
 	/* only for stats (print -1 as "%lu" may give unexpected results ;) */
 	connid = c->c_connid;
@@ -752,18 +758,24 @@ void connection_closing( Connection *c, const char *why )
 		connection_abandon( c );
 
 		/* wake write blocked operations */
-		if ( c->c_writewaiter ) {
-			ldap_pvt_thread_cond_signal( &c->c_write_cv );
-			/* ITS#4667 this may allow another thread to drop into
-			 * connection_resched / connection_close before we
-			 * finish, but that's OK.
-			 */
-			slapd_clr_write( c->c_sd, 1 );
-			ldap_pvt_thread_mutex_unlock( &c->c_mutex );
-			ldap_pvt_thread_mutex_lock( &c->c_write_mutex );
-			ldap_pvt_thread_mutex_lock( &c->c_mutex );
-			ldap_pvt_thread_mutex_unlock( &c->c_write_mutex );
+		ldap_pvt_thread_mutex_lock( &c->c_write1_mutex );
+		if ( c->c_writers > 0 ) {
+			c->c_writers = -c->c_writers;
+			ldap_pvt_thread_cond_broadcast( &c->c_write1_cv );
+			ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
+			if ( c->c_writewaiter ) {
+				ldap_pvt_thread_mutex_lock( &c->c_write2_mutex );
+				ldap_pvt_thread_cond_signal( &c->c_write2_cv );
+				slapd_clr_write( c->c_sd, 1 );
+				ldap_pvt_thread_mutex_unlock( &c->c_write2_mutex );
+			}
+			ldap_pvt_thread_mutex_lock( &c->c_write1_mutex );
+			while ( c->c_writers ) {
+				ldap_pvt_thread_cond_wait( &c->c_write1_cv, &c->c_write1_mutex );
+			}
+			ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
 		} else {
+			ldap_pvt_thread_mutex_unlock( &c->c_write1_mutex );
 			slapd_clr_write( c->c_sd, 1 );
 		}
 
@@ -778,11 +790,6 @@ connection_close( Connection *c )
 {
 	assert( connections != NULL );
 	assert( c != NULL );
-
-	/* ITS#4667 we may have gotten here twice */
-	if ( c->c_conn_state == SLAP_C_INVALID )
-		return;
-
 	assert( c->c_struct_state == SLAP_C_USED );
 	assert( c->c_conn_state == SLAP_C_CLOSING );
 
@@ -1174,7 +1181,7 @@ void connection_client_stop(
 
 	/* get (locked) connection */
 	c = connection_get( s );
-	
+
 	assert( c->c_conn_state == SLAP_C_CLIENT );
 
 	c->c_listener = NULL;
@@ -1246,6 +1253,24 @@ int connection_read_activate( ber_socket_t s )
 	return rc;
 }
 
+void
+connection_hangup( ber_socket_t s )
+{
+	Connection *c;
+
+	c = connection_get( s );
+	if ( c ) {
+		if ( c->c_conn_state == SLAP_C_CLIENT ) {
+			connection_return( c );
+			connection_read_activate( s );
+		} else {
+			connection_closing( c, "connection lost" );
+			connection_close( c );
+			connection_return( c );
+		}
+	}
+}
+
 static int
 connection_read( ber_socket_t s, conn_readinfo *cri )
 {
@@ -1831,7 +1856,7 @@ int connection_write(ber_socket_t s)
 	Debug( LDAP_DEBUG_TRACE,
 		"connection_write(%d): waking output for id=%lu\n",
 		s, c->c_connid, 0 );
-	ldap_pvt_thread_cond_signal( &c->c_write_cv );
+	ldap_pvt_thread_cond_signal( &c->c_write2_cv );
 
 	if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_READ, NULL ) ) {
 		slapd_set_read( s, 1 );
diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c
index fea9d35e2324ee5f9c57fda37ecb9922e10d709a..7f953e4d329abe40b4d3f6ed0e04da5a9d590839 100644
--- a/servers/slapd/daemon.c
+++ b/servers/slapd/daemon.c
@@ -2495,7 +2495,7 @@ slapd_daemon_task(
 #endif /* LDAP_DEBUG */
 
 		for ( i = 0; i < ns; i++ ) {
-			int rc = 1, fd;
+			int rc = 1, fd, w = 0;
 
 			if ( SLAP_EVENT_IS_LISTENER( i ) ) {
 				rc = slap_listener_activate( SLAP_EVENT_LISTENER( i ) );
@@ -2522,6 +2522,7 @@ slapd_daemon_task(
 						fd, 0, 0 );
 
 					SLAP_EVENT_CLR_WRITE( i );
+					w = 1;
 
 					/*
 					 * NOTE: it is possible that the connection was closed
@@ -2541,9 +2542,10 @@ slapd_daemon_task(
 
 					SLAP_EVENT_CLR_READ( i );
 					connection_read_activate( fd );
-				} else {
+				} else if ( !w ) {
 					Debug( LDAP_DEBUG_CONNS,
 						"daemon: hangup on %d\n", fd, 0, 0 );
+					connection_hangup( fd );
 				}
 			}
 		}
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index 5d07c4c259e5ef59a158b501552d38ba7128fab7..4b17b54a59f942ac9a4ee271118178339f09a4a9 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -745,6 +745,7 @@ LDAP_SLAPD_F (Connection *) connection_init LDAP_P((
 
 LDAP_SLAPD_F (void) connection_closing LDAP_P((
 	Connection *c, const char *why ));
+LDAP_SLAPD_F (void) connection_hangup LDAP_P(( ber_socket_t fd ));
 LDAP_SLAPD_F (int) connection_state_closing LDAP_P(( Connection *c ));
 LDAP_SLAPD_F (const char *) connection_state2str LDAP_P(( int state ))
 	LDAP_GCCATTR((const));
diff --git a/servers/slapd/result.c b/servers/slapd/result.c
index a2e7343eb6ceca4568d990848114e4a317525405..c9351fb47776d023eb0c7d1c2dc8bfe2e0dc9b58 100644
--- a/servers/slapd/result.c
+++ b/servers/slapd/result.c
@@ -137,27 +137,44 @@ static long send_ldap_ber(
 	BerElement *ber )
 {
 	ber_len_t bytes;
+	long ret = 0;
+	int closing = 0;
 
 	ber_get_option( ber, LBER_OPT_BER_BYTES_TO_WRITE, &bytes );
 
 	/* write only one pdu at a time - wait til it's our turn */
-	ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
+	ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
+	if ( connection_state_closing( conn )) {
+		ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
+		return 0;
+	}
+	while ( conn->c_writers > 0 ) {
+		ldap_pvt_thread_cond_wait( &conn->c_write1_cv, &conn->c_write1_mutex );
+	}
+	/* connection was closed under us */
+	if ( conn->c_writers < 0 ) {
+		closing = 1;
+		/* we're the last waiter, let the closer continue */
+		if ( conn->c_writers == -1 )
+			ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
+	}
 
-	/* lock the connection */ 
-	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
+	conn->c_writers++;
+	ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
+
+	if ( closing )
+		return 0;
 
 	/* write the pdu */
 	while( 1 ) {
 		int err;
 
-		if ( connection_state_closing( conn ) ) {
-			ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
-			ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
-
-			return 0;
-		}
+		/* lock the connection */ 
+		ldap_pvt_thread_mutex_lock( &conn->c_mutex );
 
 		if ( ber_flush2( conn->c_sb, ber, LBER_FLUSH_FREE_NEVER ) == 0 ) {
+			ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+			ret = bytes;
 			break;
 		}
 
@@ -176,23 +193,41 @@ static long send_ldap_ber(
 			connection_closing( conn, "connection lost on write" );
 
 			ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
-			ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
 
-			return( -1 );
+			ret = -1;
+			break;
 		}
 
 		/* wait for socket to be write-ready */
+		ldap_pvt_thread_mutex_lock( &conn->c_write2_mutex );
 		conn->c_writewaiter = 1;
 		slapd_set_write( conn->c_sd, 1 );
 
-		ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
+		ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+		ldap_pvt_thread_cond_wait( &conn->c_write2_cv, &conn->c_write2_mutex );
 		conn->c_writewaiter = 0;
+		ldap_pvt_thread_mutex_unlock( &conn->c_write2_mutex );
+		ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
+		closing = ( conn->c_writers < 0 );
+		ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
+		if ( closing ) {
+			ret = 0;
+			break;
+		}
 	}
 
-	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
-	ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
+	ldap_pvt_thread_mutex_lock( &conn->c_write1_mutex );
+	if ( conn->c_writers < 0 ) {
+		conn->c_writers++;
+		if ( !conn->c_writers )
+			ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
+	} else {
+		conn->c_writers--;
+		ldap_pvt_thread_cond_signal( &conn->c_write1_cv );
+	}
+	ldap_pvt_thread_mutex_unlock( &conn->c_write1_mutex );
 
-	return bytes;
+	return ret;
 }
 
 static int
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index dadd88d5c92db7cc444587eeb1c056e5d29f7468..b4e50e39123094c08e7a4f01222d2da3f55aa77c 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -2801,14 +2801,17 @@ struct Connection {
 	LDAP_STAILQ_HEAD(c_o, Operation) c_ops;	/* list of operations being processed */
 	LDAP_STAILQ_HEAD(c_po, Operation) c_pending_ops;	/* list of pending operations */
 
-	ldap_pvt_thread_mutex_t	c_write_mutex;	/* only one pdu written at a time */
-	ldap_pvt_thread_cond_t	c_write_cv;		/* used to wait for sd write-ready*/
+	ldap_pvt_thread_mutex_t	c_write1_mutex;	/* only one pdu written at a time */
+	ldap_pvt_thread_cond_t	c_write1_cv;	/* only one pdu written at a time */
+	ldap_pvt_thread_mutex_t	c_write2_mutex;	/* used to wait for sd write-ready */
+	ldap_pvt_thread_cond_t	c_write2_cv;	/* used to wait for sd write-ready*/
 
 	BerElement	*c_currentber;	/* ber we're attempting to read */
+	int			c_writers;		/* number of writers waiting */
 
 	char		c_sasl_bind_in_progress;	/* multi-op bind in progress */
+	char		c_writewaiter;	/* true if blocked on write */
 
-	char		c_writewaiter;	/* true if writer is waiting */
 
 #define	CONN_IS_TLS	1
 #define	CONN_IS_UDP	2
diff --git a/servers/slapd/slapi/slapi_ops.c b/servers/slapd/slapi/slapi_ops.c
index e7aab5d8d370532d92b2ed06f8a443c49777ef85..eaf4060b01739d929894a98c9ac0191b9a3bf269 100644
--- a/servers/slapd/slapi/slapi_ops.c
+++ b/servers/slapd/slapi/slapi_ops.c
@@ -224,8 +224,10 @@ slapi_int_connection_init_pb( Slapi_PBlock *pb, ber_tag_t tag )
 
 	/* should check status of thread calls */
 	ldap_pvt_thread_mutex_init( &conn->c_mutex );
-	ldap_pvt_thread_mutex_init( &conn->c_write_mutex );
-	ldap_pvt_thread_cond_init( &conn->c_write_cv );
+	ldap_pvt_thread_mutex_init( &conn->c_write1_mutex );
+	ldap_pvt_thread_mutex_init( &conn->c_write2_mutex );
+	ldap_pvt_thread_cond_init( &conn->c_write1_cv );
+	ldap_pvt_thread_cond_init( &conn->c_write2_cv );
 
 	ldap_pvt_thread_mutex_lock( &conn->c_mutex );