diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 5f59a382f1..24842a858a 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1369,17 +1369,29 @@ include_dir 'conf.d'
        </para>
 
        <para>
-        At present, this feature is supported only on Linux. The setting is
-        ignored on other systems when set to <literal>try</literal>.
+        At present, this feature is supported only on Linux and Windows. The
+        setting is ignored on other systems when set to <literal>try</literal>.
        </para>
 
        <para>
         The use of huge pages results in smaller page tables and less CPU time
-        spent on memory management, increasing performance. For more details,
+        spent on memory management, increasing performance. For more details on Linux,
         see <xref linkend="linux-huge-pages">.
        </para>
 
        <para>
+        Huge pages are known as large pages on Windows.  To use them, you need to
+        assign the user right Lock Pages in Memory to the Windows user account
+        that runs <productname>PostgreSQL</productname>.
+        You can use Windows Group Policy tool (gpedit.msc) to assign the user right
+        Lock Pages in Memory.
+        To start the database server on the command prompt as a standalone process,
+        not as a Windows service, run the command prompt as an administrator or
+        disable the User Access Control (UAC). When the UAC is enabled, the normal
+        command prompt revokes the user right Lock Pages in Memory.
+       </para>
+
+       <para>
         With <varname>huge_pages</varname> set to <literal>try</literal>,
         the server will try to use huge pages, but fall back to using
         normal allocation if that fails. With <literal>on</literal>, failure
diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c
index 01f51f3158..935f7e503e 100644
--- a/src/backend/port/win32_shmem.c
+++ b/src/backend/port/win32_shmem.c
@@ -21,6 +21,7 @@ HANDLE		UsedShmemSegID = INVALID_HANDLE_VALUE;
 void	   *UsedShmemSegAddr = NULL;
 static Size UsedShmemSegSize = 0;
 
+static bool EnableLockPagesPrivilege(int elevel);
 static void pgwin32_SharedMemoryDelete(int status, Datum shmId);
 
 /*
@@ -103,6 +104,66 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
 	return true;
 }
 
+/*
+ * EnableLockPagesPrivilege
+ *
+ * Try to acquire SeLockMemoryPrivilege so we can use large pages.
+ */
+static bool
+EnableLockPagesPrivilege(int elevel)
+{
+	HANDLE hToken;
+	TOKEN_PRIVILEGES tp;
+	LUID luid;
+
+	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+	{
+		ereport(elevel,
+				(errmsg("could not enable Lock Pages in Memory user right: error code %lu", GetLastError()),
+				 errdetail("Failed system call was %s.", "OpenProcessToken")));
+		return FALSE;
+	}
+
+	if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid))
+	{
+		ereport(elevel,
+				(errmsg("could not enable Lock Pages in Memory user right: error code %lu", GetLastError()),
+				 errdetail("Failed system call was %s.", "LookupPrivilegeValue")));
+		CloseHandle(hToken);
+		return FALSE;
+	}
+	tp.PrivilegeCount = 1;
+	tp.Privileges[0].Luid = luid;
+	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+	if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))
+	{
+		ereport(elevel,
+				(errmsg("could not enable Lock Pages in Memory user right: error code %lu", GetLastError()),
+				 errdetail("Failed system call was %s.", "AdjustTokenPrivileges")));
+		CloseHandle(hToken);
+		return FALSE;
+	}
+
+	if (GetLastError() != ERROR_SUCCESS)
+	{
+		if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
+			ereport(elevel,
+					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+					 errmsg("could not enable Lock Pages in Memory user right"),
+					 errhint("Assign Lock Pages in Memory user right to the Windows user account which runs PostgreSQL.")));
+		else
+			ereport(elevel,
+					(errmsg("could not enable Lock Pages in Memory user right: error code %lu", GetLastError()),
+					 errdetail("Failed system call was %s.", "AdjustTokenPrivileges")));
+		CloseHandle(hToken);
+		return FALSE;
+	}
+
+	CloseHandle(hToken);
+
+	return TRUE;
+}
 
 /*
  * PGSharedMemoryCreate
@@ -127,11 +188,9 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
 	int			i;
 	DWORD		size_high;
 	DWORD		size_low;
-
-	if (huge_pages == HUGE_PAGES_ON)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("huge pages not supported on this platform")));
+	SIZE_T		largePageSize = 0;
+	Size		orig_size = size;
+	DWORD		flProtect = PAGE_READWRITE;
 
 	/* Room for a header? */
 	Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
@@ -140,6 +199,35 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
 
 	UsedShmemSegAddr = NULL;
 
+	if (huge_pages == HUGE_PAGES_ON || huge_pages == HUGE_PAGES_TRY)
+	{
+		/* Does the processor support large pages? */
+		largePageSize = GetLargePageMinimum();
+		if (largePageSize == 0)
+		{
+			ereport(huge_pages == HUGE_PAGES_ON ? FATAL : DEBUG1,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("the processor does not support large pages")));
+			ereport(DEBUG1,
+					(errmsg("disabling huge pages")));
+		}
+		else if (!EnableLockPagesPrivilege(huge_pages == HUGE_PAGES_ON ? FATAL : DEBUG1))
+		{
+			ereport(DEBUG1,
+					(errmsg("disabling huge pages")));
+		}
+		else
+		{
+			/* Huge pages available and privilege enabled, so turn on */
+			flProtect = PAGE_READWRITE | SEC_COMMIT | SEC_LARGE_PAGES;
+
+			/* Round size up as appropriate. */
+			if (size % largePageSize != 0)
+				size += largePageSize - (size % largePageSize);
+		}
+	}
+
+retry:
 #ifdef _WIN64
 	size_high = size >> 32;
 #else
@@ -163,16 +251,35 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port,
 
 		hmap = CreateFileMapping(INVALID_HANDLE_VALUE,	/* Use the pagefile */
 								 NULL,	/* Default security attrs */
-								 PAGE_READWRITE,	/* Memory is Read/Write */
+								 flProtect,
 								 size_high, /* Size Upper 32 Bits	*/
 								 size_low,	/* Size Lower 32 bits */
 								 szShareMem);
 
 		if (!hmap)
-			ereport(FATAL,
-					(errmsg("could not create shared memory segment: error code %lu", GetLastError()),
-					 errdetail("Failed system call was CreateFileMapping(size=%zu, name=%s).",
-							   size, szShareMem)));
+		{
+			if (GetLastError() == ERROR_NO_SYSTEM_RESOURCES &&
+				huge_pages == HUGE_PAGES_TRY &&
+				(flProtect & SEC_LARGE_PAGES) != 0)
+			{
+				elog(DEBUG1, "CreateFileMapping(%zu) with SEC_LARGE_PAGES failed "
+					 "due to insufficient large pages, huge pages disabled",
+					 size);
+
+				/*
+				 * Use the original size, not the rounded-up value, when falling back
+				 * to non-huge pages.
+				 */
+				size = orig_size;
+				flProtect = PAGE_READWRITE;
+				goto retry;
+			}
+			else
+				ereport(FATAL,
+						(errmsg("could not create shared memory segment: error code %lu", GetLastError()),
+						 errdetail("Failed system call was CreateFileMapping(size=%zu, name=%s).",
+								   size, szShareMem)));
+		}
 
 		/*
 		 * If the segment already existed, CreateFileMapping() will return a
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index a05fb1a7eb..ff4fd2ef1f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3888,7 +3888,7 @@ static struct config_enum ConfigureNamesEnum[] =
 
 	{
 		{"huge_pages", PGC_POSTMASTER, RESOURCES_MEM,
-			gettext_noop("Use of huge pages on Linux."),
+			gettext_noop("Use of huge pages on Linux/Windows."),
 			NULL
 		},
 		&huge_pages,
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 4e02c4cea1..7d758e5c6b 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -152,6 +152,7 @@ static void WINAPI pgwin32_ServiceHandler(DWORD);
 static void WINAPI pgwin32_ServiceMain(DWORD, LPTSTR *);
 static void pgwin32_doRunAsService(void);
 static int	CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service);
+static PTOKEN_PRIVILEGES GetPrivilegesToDelete(HANDLE hToken);
 #endif
 
 static pgpid_t get_pgpid(bool is_status_request);
@@ -1631,11 +1632,6 @@ typedef BOOL (WINAPI * __SetInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, L
 typedef BOOL (WINAPI * __AssignProcessToJobObject) (HANDLE, HANDLE);
 typedef BOOL (WINAPI * __QueryInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD, LPDWORD);
 
-/* Windows API define missing from some versions of MingW headers */
-#ifndef  DISABLE_MAX_PRIVILEGE
-#define DISABLE_MAX_PRIVILEGE	0x1
-#endif
-
 /*
  * Create a restricted token, a job object sandbox, and execute the specified
  * process with it.
@@ -1658,6 +1654,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_ser
 	HANDLE		restrictedToken;
 	SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
 	SID_AND_ATTRIBUTES dropSids[2];
+	PTOKEN_PRIVILEGES delPrivs;
 
 	/* Functions loaded dynamically */
 	__CreateRestrictedToken _CreateRestrictedToken = NULL;
@@ -1716,11 +1713,17 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_ser
 		return 0;
 	}
 
+	/* Get list of privileges to remove */
+	delPrivs = GetPrivilegesToDelete(origToken);
+	if (delPrivs == NULL)
+		/* The message was output in the function */
+		return 0;
+
 	b = _CreateRestrictedToken(origToken,
-							   DISABLE_MAX_PRIVILEGE,
+							   0,
 							   sizeof(dropSids) / sizeof(dropSids[0]),
 							   dropSids,
-							   0, NULL,
+							   delPrivs->PrivilegeCount, delPrivs->Privileges,
 							   0, NULL,
 							   &restrictedToken);
 
@@ -1840,6 +1843,67 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_ser
 	 */
 	return r;
 }
+
+/*
+ * Get a list of privileges to delete from the access token.
+ * We used to delete all privileges (except SeChangeNotifyName) by passing
+ * DISABLE_MAX_PRIVILEGE when we invoke postgres.exe. However, we need to retain
+ * SeLockMemoryPrivilege for large pages.
+ * So, we delete particular privileges instead by passing.
+ */
+static PTOKEN_PRIVILEGES
+GetPrivilegesToDelete(HANDLE hToken)
+{
+	int			i, j;
+	DWORD		length;
+	PTOKEN_PRIVILEGES tokenPrivs;
+	LUID		luidLockPages;
+	LUID		luidChangeNotify;
+
+	if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luidLockPages) ||
+		!LookupPrivilegeValue(NULL, SE_CHANGE_NOTIFY_NAME, &luidChangeNotify))
+	{
+		write_stderr(_("%s: could not get LUIDs for privileges: error code %lu\n"),
+					 progname, (unsigned long) GetLastError());
+		return NULL;
+	}
+
+	if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &length) &&
+		GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+	{
+		write_stderr(_("%s: could not get token information: error code %lu\n"),
+					 progname, (unsigned long) GetLastError());
+		return NULL;
+	}
+
+	tokenPrivs = (PTOKEN_PRIVILEGES) malloc(length);
+	if (tokenPrivs == NULL)
+	{
+		write_stderr(_("%s: out of memory\n"), progname);
+		return NULL;
+	}
+
+	if (!GetTokenInformation(hToken, TokenPrivileges, tokenPrivs, length, &length))
+	{
+		write_stderr(_("%s: could not get token information: error code %lu\n"),
+					 progname, (unsigned long) GetLastError());
+		free(tokenPrivs);
+		return NULL;
+	}
+
+	for (i = 0; i < tokenPrivs->PrivilegeCount; i++)
+	{
+		if (memcmp(&tokenPrivs->Privileges[i].Luid, &luidLockPages, sizeof(LUID)) == 0 ||
+			memcmp(&tokenPrivs->Privileges[i].Luid, &luidChangeNotify, sizeof(LUID)) == 0)
+		{
+			for (j = i; j < tokenPrivs->PrivilegeCount - 1; j++)
+				tokenPrivs->Privileges[j] = tokenPrivs->Privileges[j + 1];
+			tokenPrivs->PrivilegeCount--;
+		}
+	}
+
+	return tokenPrivs;
+}
 #endif							/* WIN32 */
 
 static void
