diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c
index f70e3e98b1cfa24f1e4e9a8534b47b95b62a8c5c..d7acd43b938fd6ca7d9b798e84c2c19bb93232bf 100644
--- a/src/backend/port/sysv_shmem.c
+++ b/src/backend/port/sysv_shmem.c
@@ -211,7 +211,7 @@ InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
 
 /****************************************************************************/
 /*	IpcMemoryDetach(status, shmaddr)	removes a shared memory segment		*/
-/*										from process' address spaceq		*/
+/*										from process' address space			*/
 /*	(called as an on_shmem_exit callback, hence funny argument list)		*/
 /****************************************************************************/
 static void
@@ -455,9 +455,10 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
 /*
  * PGSharedMemoryReAttach
  *
- * Re-attach to an already existing shared memory segment.  In the non
- * EXEC_BACKEND case this is not used, because postmaster children inherit
- * the shared memory segment attachment via fork().
+ * This is called during startup of a postmaster child process to re-attach to
+ * an already existing shared memory segment.  This is needed only in the
+ * EXEC_BACKEND case; otherwise postmaster children inherit the shared memory
+ * segment attachment via fork().
  *
  * UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this
  * routine.  The caller must have already restored them to the postmaster's
@@ -490,16 +491,52 @@ PGSharedMemoryReAttach(void)
 
 	UsedShmemSegAddr = hdr;		/* probably redundant */
 }
+
+/*
+ * PGSharedMemoryNoReAttach
+ *
+ * This is called during startup of a postmaster child process when we choose
+ * *not* to re-attach to the existing shared memory segment.  We must clean up
+ * to leave things in the appropriate state.  This is not used in the non
+ * EXEC_BACKEND case, either.
+ *
+ * The child process startup logic might or might not call PGSharedMemoryDetach
+ * after this; make sure that it will be a no-op if called.
+ *
+ * UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this
+ * routine.  The caller must have already restored them to the postmaster's
+ * values.
+ */
+void
+PGSharedMemoryNoReAttach(void)
+{
+	Assert(UsedShmemSegAddr != NULL);
+	Assert(IsUnderPostmaster);
+
+#ifdef __CYGWIN__
+	/* cygipc (currently) appears to not detach on exec. */
+	PGSharedMemoryDetach();
+#endif
+
+	/* For cleanliness, reset UsedShmemSegAddr to show we're not attached. */
+	UsedShmemSegAddr = NULL;
+	/* And the same for UsedShmemSegID. */
+	UsedShmemSegID = 0;
+}
+
 #endif   /* EXEC_BACKEND */
 
 /*
  * PGSharedMemoryDetach
  *
  * Detach from the shared memory segment, if still attached.  This is not
- * intended for use by the process that originally created the segment
- * (it will have an on_shmem_exit callback registered to do that).  Rather,
- * this is for subprocesses that have inherited an attachment and want to
- * get rid of it.
+ * intended to be called explicitly by the process that originally created the
+ * segment (it will have an on_shmem_exit callback registered to do that).
+ * Rather, this is for subprocesses that have inherited an attachment and want
+ * to get rid of it.
+ *
+ * UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this
+ * routine.
  */
 void
 PGSharedMemoryDetach(void)
diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c
index ba9f2480db826677b2a203681548c2637401b209..fd10e25328422c1bca5afb0b5aa6682d65face4f 100644
--- a/src/backend/port/win32_shmem.c
+++ b/src/backend/port/win32_shmem.c
@@ -16,7 +16,7 @@
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
 
-HANDLE		UsedShmemSegID = 0;
+HANDLE		UsedShmemSegID = INVALID_HANDLE_VALUE;
 void	   *UsedShmemSegAddr = NULL;
 static Size UsedShmemSegSize = 0;
 
@@ -82,7 +82,6 @@ GetSharedMemName(void)
  * we only care about shmem segments that are associated with the intended
  * DataDir.  This is an important consideration since accidental matches of
  * shmem segment IDs are reasonably common.
- *
  */
 bool
 PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
@@ -114,7 +113,6 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
  * or recycle any existing segment. On win32, we always create a new segment,
  * since there is no need for recycling (segments go away automatically
  * when the last backend exits)
- *
  */
 PGShmemHeader *
 PGSharedMemoryCreate(Size size, bool makePrivate, int port)
@@ -211,9 +209,6 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
 		elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError());
 
 
-	/* Register on-exit routine to delete the new segment */
-	on_shmem_exit(pgwin32_SharedMemoryDelete, PointerGetDatum(hmap2));
-
 	/*
 	 * Get a pointer to the new shared memory segment. Map the whole segment
 	 * at once, and let the system decide on the initial address.
@@ -246,14 +241,18 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
 	UsedShmemSegSize = size;
 	UsedShmemSegID = hmap2;
 
+	/* Register on-exit routine to delete the new segment */
+	on_shmem_exit(pgwin32_SharedMemoryDelete, PointerGetDatum(hmap2));
+
 	return hdr;
 }
 
 /*
  * PGSharedMemoryReAttach
  *
- * Re-attach to an already existing shared memory segment. Use the
- * handle inherited from the postmaster.
+ * This is called during startup of a postmaster child process to re-attach to
+ * an already existing shared memory segment, using the handle inherited from
+ * the postmaster.
  *
  * UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this
  * routine.  The caller must have already restored them to the postmaster's
@@ -288,37 +287,88 @@ PGSharedMemoryReAttach(void)
 	UsedShmemSegAddr = hdr;		/* probably redundant */
 }
 
+/*
+ * PGSharedMemoryNoReAttach
+ *
+ * This is called during startup of a postmaster child process when we choose
+ * *not* to re-attach to the existing shared memory segment.  We must clean up
+ * to leave things in the appropriate state.
+ *
+ * The child process startup logic might or might not call PGSharedMemoryDetach
+ * after this; make sure that it will be a no-op if called.
+ *
+ * UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this
+ * routine.  The caller must have already restored them to the postmaster's
+ * values.
+ */
+void
+PGSharedMemoryNoReAttach(void)
+{
+	Assert(UsedShmemSegAddr != NULL);
+	Assert(IsUnderPostmaster);
+
+	/*
+	 * Under Windows we will not have mapped the segment, so we don't need to
+	 * un-map it.  Just reset UsedShmemSegAddr to show we're not attached.
+	 */
+	UsedShmemSegAddr = NULL;
+
+	/*
+	 * We *must* close the inherited shmem segment handle, else Windows will
+	 * consider the existence of this process to mean it can't release the
+	 * shmem segment yet.  We can now use PGSharedMemoryDetach to do that.
+	 */
+	PGSharedMemoryDetach();
+}
+
 /*
  * PGSharedMemoryDetach
  *
  * Detach from the shared memory segment, if still attached.  This is not
- * intended for use by the process that originally created the segment. Rather,
- * this is for subprocesses that have inherited an attachment and want to
- * get rid of it.
+ * intended to be called explicitly by the process that originally created the
+ * segment (it will have an on_shmem_exit callback registered to do that).
+ * Rather, this is for subprocesses that have inherited an attachment and want
+ * to get rid of it.
+ *
+ * UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this
+ * routine.
  */
 void
 PGSharedMemoryDetach(void)
 {
+	/* Unmap the view, if it's mapped */
 	if (UsedShmemSegAddr != NULL)
 	{
 		if (!UnmapViewOfFile(UsedShmemSegAddr))
-			elog(LOG, "could not unmap view of shared memory: error code %lu", GetLastError());
+			elog(LOG, "could not unmap view of shared memory: error code %lu",
+				 GetLastError());
 
 		UsedShmemSegAddr = NULL;
 	}
+
+	/* And close the shmem handle, if we have one */
+	if (UsedShmemSegID != INVALID_HANDLE_VALUE)
+	{
+		if (!CloseHandle(UsedShmemSegID))
+			elog(LOG, "could not close handle to shared memory: error code %lu",
+				 GetLastError());
+
+		UsedShmemSegID = INVALID_HANDLE_VALUE;
+	}
 }
 
 
 /*
- *	pgwin32_SharedMemoryDelete(status, shmId)		deletes a shared memory segment
- *	(called as an on_shmem_exit callback, hence funny argument list)
+ * pgwin32_SharedMemoryDelete
+ *
+ * Detach from and delete the shared memory segment
+ * (called as an on_shmem_exit callback, hence funny argument list)
  */
 static void
 pgwin32_SharedMemoryDelete(int status, Datum shmId)
 {
+	Assert(DatumGetPointer(shmId) == UsedShmemSegID);
 	PGSharedMemoryDetach();
-	if (!CloseHandle(DatumGetPointer(shmId)))
-		elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError());
 }
 
 /*
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 40e655f685555c832b4fbc6b4cd4fdf97fa6bd56..2b16e3e26b2f9a9822adb3bf29c6424c6b95efd1 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -4175,13 +4175,16 @@ SubPostmasterMain(int argc, char *argv[])
 	/*
 	 * If appropriate, physically re-attach to shared memory segment. We want
 	 * to do this before going any further to ensure that we can attach at the
-	 * same address the postmaster used.
+	 * same address the postmaster used.  On the other hand, if we choose not
+	 * to re-attach, we may have other cleanup to do.
 	 */
 	if (strcmp(argv[1], "--forkbackend") == 0 ||
 		strcmp(argv[1], "--forkavlauncher") == 0 ||
 		strcmp(argv[1], "--forkavworker") == 0 ||
 		strcmp(argv[1], "--forkboot") == 0)
 		PGSharedMemoryReAttach();
+	else
+		PGSharedMemoryNoReAttach();
 
 	/* autovacuum needs this set before calling InitProcess */
 	if (strcmp(argv[1], "--forkavlauncher") == 0)
diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h
index dc88a36dd611854573f67290c40bd3a5287e973c..aad13bd2acea3f3a1a2d92659ade663ccda6fed4 100644
--- a/src/include/storage/pg_shmem.h
+++ b/src/include/storage/pg_shmem.h
@@ -48,6 +48,7 @@ extern HANDLE UsedShmemSegID;
 extern void *UsedShmemSegAddr;
 
 extern void PGSharedMemoryReAttach(void);
+extern void PGSharedMemoryNoReAttach(void);
 #endif
 
 extern PGShmemHeader *PGSharedMemoryCreate(Size size, bool makePrivate,