diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 83d8f53a9a7d2fccac25ba13dca4594759e289be..98d16f62bdf30c15252003f6cdbb73dfcd35724d 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2844,7 +2844,33 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli,
 		XLogFilePath(xlogfpath, tli, log, seg);
 		if (stat(xlogfpath, &statbuf) == 0)
 		{
-			if (unlink(xlogfpath) != 0)
+			char oldpath[MAXPGPATH];
+#ifdef WIN32
+			static unsigned int deletedcounter = 1;
+			/*
+			 * On Windows, if another process (e.g a walsender process) holds
+			 * the file open in FILE_SHARE_DELETE mode, unlink will succeed,
+			 * but the file will still show up in directory listing until the
+			 * last handle is closed, and we cannot rename the new file in its
+			 * place until that. To avoid that problem, rename the old file to
+			 * a temporary name first. Use a counter to create a unique
+			 * filename, because the same file might be restored from the
+			 * archive multiple times, and a walsender could still be holding
+			 * onto an old deleted version of it.
+			 */
+			snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
+					 xlogfpath, deletedcounter++);
+			if (rename(xlogfpath, oldpath) != 0)
+			{
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not rename file \"%s\" to \"%s\": %m",
+								xlogfpath, oldpath)));
+			}
+#else
+			strncpy(oldpath, xlogfpath, MAXPGPATH);
+#endif
+			if (unlink(oldpath) != 0)
 				ereport(FATAL,
 						(errcode_for_file_access(),
 						 errmsg("could not remove file \"%s\": %m",