diff --git a/src/box/recovery.cc b/src/box/recovery.cc
index e0677ec503283a8e0ae51f9c29ae576cc41baca3..a35d3608e5d97e2ceba681bb9755cb6f00f17945 100644
--- a/src/box/recovery.cc
+++ b/src/box/recovery.cc
@@ -337,8 +337,12 @@ recovery_bootstrap(struct recovery *r)
 static void
 recover_remaining_wals(struct recovery *r)
 {
-	xdir_scan_xc(&r->wal_dir);
-
+	/*
+	 * Sic: it could be tempting to put xdir_scan() inside
+	 * this function. This would slow down relay quite a bit,
+	 * since xdir_scan() would be invoked on every relay
+	 * row.
+	 */
 	struct vclock *last = vclockset_last(&r->wal_dir.index);
 	if (last == NULL) {
 		if (r->current_wal != NULL) {
@@ -412,6 +416,7 @@ recovery_finalize(struct recovery *r, enum wal_mode wal_mode,
 {
 	recovery_stop_local(r);
 
+	xdir_scan_xc(&r->wal_dir);
 	recover_remaining_wals(r);
 
 	recovery_close_log(r);
@@ -554,7 +559,34 @@ recovery_follow_f(va_list ap)
 
 	while (! fiber_is_cancelled()) {
 
-		recover_remaining_wals(r);
+		/*
+		 * Recover until there is no new stuff which appeared in
+		 * the log dir while recovery was running.
+		 *
+		 * Use vclock signature to represent the current wal
+		 * since the xlog object itself may be freed in
+		 * recover_remaining_rows().
+		 */
+		int64_t start, end;
+		do {
+			start = r->current_wal ? vclock_sum(&r->current_wal->vclock) : 0;
+			/*
+			 * If there is no current WAL, or we reached
+			 * an end  of one, look for new WALs.
+			 */
+			if (r->current_wal == NULL || r->current_wal->eof_read)
+				xdir_scan_xc(&r->wal_dir);
+
+			recover_remaining_wals(r);
+
+			end = r->current_wal ? vclock_sum(&r->current_wal->vclock) : 0;
+			/*
+			 * Continue, given there's been progress *and* there is a
+			 * chance new WALs have appeared since.
+			 * Sic: end * is < start (is 0) if someone deleted all logs
+			 * on the filesystem.
+			 */
+		} while (end > start && (r->current_wal == NULL || r->current_wal->eof_read));
 
 		subscription.set_log_path(
 			r->current_wal != NULL ? r->current_wal->filename : NULL);
@@ -583,6 +615,7 @@ recovery_follow_local(struct recovery *r, const char *name,
 	 * Scan wal_dir and recover all existing at the moment xlogs.
 	 * Blocks until finished.
 	 */
+	xdir_scan_xc(&r->wal_dir);
 	recover_remaining_wals(r);
 	recovery_close_log(r);