diff --git a/configure b/configure
index 2f094716c7..cbb642c968 100755
--- a/configure
+++ b/configure
@@ -16414,6 +16414,12 @@ if test "$PORTNAME" = "cygwin"; then
  ;;
 esac
 
+  case " $LIBOBJS " in
+  *" open.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS open.$ac_objext"
+ ;;
+esac
+
 fi
 
 ac_fn_c_check_func "$LINENO" "syslog" "ac_cv_func_syslog"
diff --git a/configure.in b/configure.in
index 854eba2d3a..8c6e48d2c2 100644
--- a/configure.in
+++ b/configure.in
@@ -1856,6 +1856,7 @@ fi
 # Cygwin needs only a bit of that
 if test "$PORTNAME" = "cygwin"; then
   AC_LIBOBJ(dirmod)
+  AC_LIBOBJ(open)
 fi
 
 AC_CHECK_FUNC(syslog,
diff --git a/src/include/port.h b/src/include/port.h
index ebcee1c55c..0db3beba0c 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -312,6 +312,20 @@ extern int	gettimeofday(struct timeval *tp, struct timezone *tzp);
 #define closesocket close
 #endif							/* WIN32 */
 
+#if defined(__CYGWIN__)
+
+/*
+ * open() and fopen() replacements to handle busy and
+ * "delete pending" files.
+ */
+
+extern int	cygwin_open(const char *, int,...);
+extern FILE *cygwin_fopen(const char *, const char *);
+#define		open(a,b,c) cygwin_open(a,b,c)
+#define		fopen(a,b) cygwin_fopen(a,b)
+
+#endif
+
 /*
  * On Windows, setvbuf() does not support _IOLBF mode, and interprets that
  * as _IOFBF.  To add insult to injury, setvbuf(file, NULL, _IOFBF, 0)
diff --git a/src/port/open.c b/src/port/open.c
index 24af6f48bf..a7f9685d4b 100644
--- a/src/port/open.c
+++ b/src/port/open.c
@@ -11,7 +11,7 @@
  *-------------------------------------------------------------------------
  */
 
-#ifdef WIN32
+#if defined(WIN32) || defined(__CYGWIN__)
 
 #ifndef FRONTEND
 #include "postgres.h"
@@ -20,8 +20,12 @@
 #endif
 
 #include <fcntl.h>
+#include <unistd.h>
 #include <assert.h>
 #include <sys/stat.h>
+#endif
+
+#if defined(WIN32) && !defined(__CYGWIN__)
 
 
 static int
@@ -214,3 +218,125 @@ pgwin32_fopen(const char *fileName, const char *mode)
 }
 
 #endif
+
+#if defined(__CYGWIN__)
+
+/*
+ * Here, "open" means the platform's function not cygwin_open,
+ * and likewise for "fopen".
+ */
+
+#undef open
+#undef fopen
+
+int
+cygwin_open(const char *fileName, int fileFlags,...)
+{
+	int			fd;
+	int			loops = 0;
+
+	while ((fd = open(fileName, fileFlags)) == -1) {
+		/*
+		 * EBUSY error (sharing violation or locking error) can occur when
+		 * the file is renamed concurrently or can indicate antivirus, backup
+		 * or similar software that's locking the file.  Wait a bit and try
+		 * again, giving up after 30 seconds.
+		 */
+		if (errno == EBUSY) {
+#ifndef FRONTEND
+			if (loops == 50)
+				ereport(LOG,
+						(errmsg("could not open file \"%s\": %s", fileName,
+								_("sharing violation")),
+						 errdetail("Continuing to retry for 30 seconds."),
+						 errhint("You might have antivirus, backup, or similar software interfering with the database system.")));
+#endif
+
+			if (loops < 300)
+			{
+				pg_usleep(100000);
+				loops++;
+				continue;
+			}
+		}
+		/*
+		 * EACCES is returned if the file is deleted but not yet
+		 * gone (see pgwin32_open for details).
+		 */
+		if (errno == EACCES) {
+			if (loops < 10)
+			{
+				/*
+				 * In case of conflict with a concurrent rename, the stat()
+				 * function can return 0, so it can't be used here as
+				 * in pgwin32_open().
+				 * But opening a directory doesn't lead to EACCES on cygwin,
+				 * so unnecessary wait for 1 second will happen only in case
+				 * of an actual file-permissions problem.
+				 */
+				pg_usleep(100000);
+				loops++;
+				continue;
+			}
+		}
+		return -1;
+	}
+	return fd;
+}
+
+FILE *
+cygwin_fopen(const char *fileName, const char *mode)
+{
+	FILE *		fp;
+	int			loops = 0;
+	while ((fp = fopen(fileName, mode)) == NULL) {
+		/*
+		 * EBUSY error (sharing violation or locking error) can occur when
+		 * the file is renamed concurrently or can indicate antivirus, backup
+		 * or similar software that's locking the file.  Wait a bit and try
+		 * again, giving up after 30 seconds.
+		 */
+		if (errno == EBUSY) {
+#ifndef FRONTEND
+			if (loops == 50)
+				ereport(LOG,
+						(errmsg("could not open file \"%s\": %s", fileName,
+								_("sharing violation")),
+						 errdetail("Continuing to retry for 30 seconds."),
+						 errhint("You might have antivirus, backup, or similar software interfering with the database system.")));
+#endif
+
+			if (loops < 300)
+			{
+				pg_usleep(100000);
+				loops++;
+				continue;
+			}
+		}
+
+		/*
+		 * EACCES is returned if the file is deleted but not yet
+		 * gone (see pgwin32_open for details).
+		 */
+		if (errno == EACCES) {
+			if (loops < 10)
+			{
+				/*
+				 * In case of conflict with a concurrent rename, the stat()
+				 * function can return 0, so it can't be used here as
+				 * in pgwin32_open().
+				 * But opening a directory doesn't lead to EACCES on cygwin,
+				 * so unnecessary wait for 1 second will happen only in case
+				 * of an actual file-permissions problem.
+				 */
+				pg_usleep(100000);
+				loops++;
+				continue;
+			}
+		}
+		return NULL;
+	}
+	return fp;
+}
+
+#endif
