diff --git a/servers/slapd/overlays/accesslog.c b/servers/slapd/overlays/accesslog.c
index 4804205c80421b81bd8606e6c29f060851511e08..d499343b6696d873a6eacadaaaedf0587af7523d 100644
--- a/servers/slapd/overlays/accesslog.c
+++ b/servers/slapd/overlays/accesslog.c
@@ -1490,9 +1490,17 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
 	if ( lo->mask & LOG_OP_WRITES ) {
 		slap_callback *cb;
 
-		/* These internal ops are not logged */
-		if ( op->o_dont_replicate && op->orm_no_opattrs )
+		/* Most internal ops are not logged */
+		if ( op->o_dont_replicate) {
+			/* Let contextCSN updates from syncrepl thru; the underlying
+			 * syncprov needs to see them. Skip others.
+			 */
+			if (( op->o_tag != LDAP_REQ_MODIFY ||
+				op->orm_modlist->sml_op != LDAP_MOD_REPLACE ||
+				op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) &&
+				op->orm_no_opattrs )
 			return SLAP_CB_CONTINUE;
+		}
 
 		ldap_pvt_thread_mutex_lock( &li->li_log_mutex );
 		old = li->li_old;
@@ -1831,10 +1839,29 @@ static int accesslog_response(Operation *op, SlapReply *rs) {
 	op2.o_req_ndn = e->e_nname;
 	op2.ora_e = e;
 	op2.o_callback = &nullsc;
+	op2.o_csn = op->o_csn;
+	/* contextCSN updates may still reach here */
+	op2.o_dont_replicate = op->o_dont_replicate;
 
 	if (( lo->mask & LOG_OP_WRITES ) && !BER_BVISEMPTY( &op->o_csn )) {
-		slap_queue_csn( &op2, &op->o_csn );
-		do_graduate = 1;
+		struct berval maxcsn;
+		char cbuf[LDAP_PVT_CSNSTR_BUFSIZE];
+		int foundit;
+		cbuf[0] = '\0';
+		maxcsn.bv_val = cbuf;
+		maxcsn.bv_len = sizeof(cbuf);
+		/* If there was a commit CSN on the main DB,
+		 * we must propagate it to the log DB for its
+		 * own syncprov. Otherwise, don't generate one.
+		 */
+		slap_get_commit_csn( op, &maxcsn, &foundit );
+		if ( !BER_BVISEMPTY( &maxcsn ) ) {
+			slap_queue_csn( &op2, &op->o_csn );
+			do_graduate = 1;
+		} else {
+			attr_merge_normalize_one( e, slap_schema.si_ad_entryCSN,
+				&op->o_csn, op->o_tmpmemctx );
+		}
 	}
 
 	op2.o_bd->be_add( &op2, &rs2 );
@@ -1922,8 +1949,18 @@ accesslog_op_mod( Operation *op, SlapReply *rs )
 	int doit = 0;
 
 	/* These internal ops are not logged */
-	if ( op->o_dont_replicate && op->orm_no_opattrs )
+	if ( op->o_dont_replicate ) {
+		/* Let contextCSN updates from syncrepl thru; the underlying
+		 * syncprov needs to see them. Skip others.
+		 */
+		if (( op->o_tag != LDAP_REQ_MODIFY ||
+			op->orm_modlist->sml_op != LDAP_MOD_REPLACE ||
+			op->orm_modlist->sml_desc != slap_schema.si_ad_contextCSN ) &&
+			op->orm_no_opattrs )
 		return SLAP_CB_CONTINUE;
+		/* give this a unique timestamp */
+		op->o_tincr++;
+	}
 
 	logop = accesslog_op2logop( op );
 	lo = logops+logop+EN_OFFSET;
diff --git a/servers/slapd/overlays/syncprov.c b/servers/slapd/overlays/syncprov.c
index d2da4c718133228053e2bf4bbcccd82d5812f1af..69be484165452ff6d7e4b4491188250ab1ef277c 100644
--- a/servers/slapd/overlays/syncprov.c
+++ b/servers/slapd/overlays/syncprov.c
@@ -1915,10 +1915,13 @@ syncprov_op_response( Operation *op, SlapReply *rs )
 			} else {
 			ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock );
 			}
+			if ( csn_changed )
+				si->si_numops++;
 			goto leave;
 		}
 
-		si->si_numops++;
+		if ( csn_changed )
+			si->si_numops++;
 		if ( si->si_chkops || si->si_chktime ) {
 			/* Never checkpoint adding the context entry,
 			 * it will deadlock
@@ -2489,6 +2492,28 @@ syncprov_op_search( Operation *op, SlapReply *rs )
 		return rs->sr_err;
 	}
 
+	/* snapshot the ctxcsn */
+	ldap_pvt_thread_rdwr_rlock( &si->si_csn_rwlock );
+	numcsns = si->si_numcsns;
+	if ( numcsns ) {
+		ber_bvarray_dup_x( &ctxcsn, si->si_ctxcsn, op->o_tmpmemctx );
+		sids = op->o_tmpalloc( numcsns * sizeof(int), op->o_tmpmemctx );
+		for ( i=0; i<numcsns; i++ )
+			sids[i] = si->si_sids[i];
+	} else {
+		ctxcsn = NULL;
+		sids = NULL;
+	}
+	dirty = si->si_dirty;
+	ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock );
+
+	/* We know nothing - do nothing */
+	if ( !numcsns ) {
+		rs->sr_err = LDAP_SUCCESS;
+		send_ldap_result( op, rs );
+		return rs->sr_err;
+	}
+
 	srs = op->o_controls[slap_cids.sc_LDAPsync];
 
 	/* If this is a persistent search, set it up right away */
@@ -2550,21 +2575,6 @@ syncprov_op_search( Operation *op, SlapReply *rs )
 		ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex );
 	}
 
-	/* snapshot the ctxcsn */
-	ldap_pvt_thread_rdwr_rlock( &si->si_csn_rwlock );
-	numcsns = si->si_numcsns;
-	if ( numcsns ) {
-		ber_bvarray_dup_x( &ctxcsn, si->si_ctxcsn, op->o_tmpmemctx );
-		sids = op->o_tmpalloc( numcsns * sizeof(int), op->o_tmpmemctx );
-		for ( i=0; i<numcsns; i++ )
-			sids[i] = si->si_sids[i];
-	} else {
-		ctxcsn = NULL;
-		sids = NULL;
-	}
-	dirty = si->si_dirty;
-	ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock );
-	
 	/* If we have a cookie, handle the PRESENT lookups */
 	if ( srs->sr_state.ctxcsn ) {
 		sessionlog *sl;
@@ -3155,7 +3165,7 @@ syncprov_db_open(
 		char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
 		struct berval csn;
 
-		if ( SLAP_SYNC_SHADOW( op->o_bd )) {
+		if ( slap_serverID || SLAP_SYNC_SHADOW( op->o_bd )) {
 		/* If we're also a consumer, then don't generate anything.
 		 * Wait for our provider to send it to us, or for a local
 		 * modify if we have multimaster.