diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index 2562eb5..3ae60f4 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -234,6 +234,7 @@ pg_perm_setlocale(int category, const char *locale)
 			result = IsoLocaleName(locale);
 			if (result == NULL)
 				result = (char *) locale;
+			elog(DEBUG3, "IsoLocaleName() executed; locale: \"%s\"", result);
 #endif							/* WIN32 */
 			break;
 #endif							/* LC_MESSAGES */
@@ -971,25 +972,97 @@ cache_locale_time(void)
  * string.  Furthermore, msvcr110.dll changed the undocumented _locale_t
  * content to carry locale names instead of locale identifiers.
  *
- * MinGW headers declare _create_locale(), but msvcrt.dll lacks that symbol.
- * IsoLocaleName() always fails in a MinGW-built postgres.exe, so only
- * Unix-style values of the lc_messages GUC can elicit localized messages.  In
- * particular, every lc_messages setting that initdb can select automatically
- * will yield only C-locale messages.  XXX This could be fixed by running the
- * fully-qualified locale name through a lookup table.
+ * MinGW headers declare _create_locale(), but msvcrt.dll lacks that symbol in
+ * releases before Windows 8. IsoLocaleName() always fails in a MinGW-built
+ * postgres.exe, so only Unix-style values of the lc_messages GUC can elicit
+ * localized messages. In particular, every lc_messages setting that initdb
+ * can select automatically will yield only C-locale messages. XXX This could
+ * be fixed by running the fully-qualified locale name through a lookup table
+ * or using EnumSystemLocalesEx() from Windows Vista/2008.
  *
  * This function returns a pointer to a static buffer bearing the converted
  * name or NULL if conversion fails.
  *
- * [1] http://msdn.microsoft.com/en-us/library/windows/desktop/dd373763.aspx
- * [2] http://msdn.microsoft.com/en-us/library/windows/desktop/dd373814.aspx
+ * [1] https://docs.microsoft.com/en-us/windows/win32/intl/locale-identifiers
+ * [2] https://docs.microsoft.com/en-us/windows/win32/intl/locale-names
  */
+
+#if _MSC_VER >= 1900
+/*
+ * Callback function for EnumSystemLocalesEx() in IsoLocaleName().
+ *
+ * This search is done by enumerating all system locales, trying to match a
+ * locale with the format: <Language>[_<Country>], e.g. English[_United States]
+ *
+ * The input is a three wchar_t array as an LPARAM. The first element is the
+ * locale_name we want to match, the second element is an allocated buffer
+ * where the IETF-standardized format locale is copied if a match is found,
+ * and the third element is the search status, 1 if a match was found,
+ * 0 otherwise.
+ */
+static BOOL CALLBACK
+search_locale_enum(LPWSTR pStr, DWORD dwFlags, LPARAM lparam)
+{
+	wchar_t		test_locale[LOCALE_NAME_MAX_LENGTH];
+	wchar_t	  **argv;
+
+	(void) (dwFlags);
+
+	argv = (wchar_t**) lparam;
+	*argv[2] = (wchar_t) 0;
+
+	memset(test_locale, 0, sizeof(test_locale));
+	/* Get the name of the <Language> in English */
+	if (GetLocaleInfoEx(pStr, LOCALE_SENGLISHLANGUAGENAME,
+						test_locale, LOCALE_NAME_MAX_LENGTH))
+	{
+		/*
+		 * If the enumerated locale does not have a hyphen ("en") OR  the
+		 * lc_message input does not have an underscore ("English"), we only
+		 * need to compare the <Language> tags.
+		 */
+		if (wcsrchr(pStr, '-') == NULL || wcsrchr(argv[0], '_') == NULL)
+		{
+			if (_wcsicmp(argv[0], test_locale) == 0)
+			{
+				wcscpy(argv[1], pStr);
+				*argv[2] = (wchar_t) 1;
+				return FALSE;
+			}
+		}
+		/*
+		 * We have to compare a full <Language>_<Country> tag, so we append
+		 * the underscore and name of the country/region in English, e.g.
+		 * "English_United States".
+		 */
+		else
+		{
+			size_t		len;
+
+			wcscat(test_locale, L"_");
+			len = wcslen(test_locale);
+			if (GetLocaleInfoEx(pStr, LOCALE_SENGLISHCOUNTRYNAME,
+								test_locale + len,
+								LOCALE_NAME_MAX_LENGTH - len))
+			{
+				if (_wcsicmp(argv[0], test_locale) == 0)
+				{
+					wcscpy(argv[1], pStr);
+					*argv[2] = (wchar_t) 1;
+					return FALSE;
+				}
+			}
+		}
+	}
+	return TRUE;
+}
+#endif							/* _MSC_VER >= 1900 */
+
 static char *
 IsoLocaleName(const char *winlocname)
 {
-#ifdef _MSC_VER
-	static char iso_lc_messages[32];
-	_locale_t	loct = NULL;
+#if defined(_MSC_VER)
+	static char	iso_lc_messages[LOCALE_NAME_MAX_LENGTH];
 
 	if (pg_strcasecmp("c", winlocname) == 0 ||
 		pg_strcasecmp("posix", winlocname) == 0)
@@ -997,17 +1070,73 @@ IsoLocaleName(const char *winlocname)
 		strcpy(iso_lc_messages, "C");
 		return iso_lc_messages;
 	}
-
-	loct = _create_locale(LC_CTYPE, winlocname);
-	if (loct != NULL)
+	else
 	{
-		size_t		rc;
+		size_t		rc = -1;
 		char	   *hyphen;
+#if _MSC_VER >= 1900
+		wchar_t		wc_locale_name[LOCALE_NAME_MAX_LENGTH];
+		wchar_t		buffer[LOCALE_NAME_MAX_LENGTH];
+		char	   *period;
+		int			len;
+		int			ret_val;
+
+		/*
+		 * Valid locales have the following syntax:
+		 * <Language>[_<Country>[.<CodePage>]]
+		 *
+		 * GetLocaleInfoEx can only take locale name without code-page and for
+		 * the purpose of this API the code-page doesn't matter.
+		 */
+		period = strchr(winlocname, '.');
+		if (period != NULL)
+			len = period - winlocname;
+		else
+			len = pg_mbstrlen(winlocname);
+
+		memset(wc_locale_name, 0, sizeof(wc_locale_name));
+		memset(buffer, 0, sizeof(buffer));
+		MultiByteToWideChar(CP_ACP, 0, winlocname, len, wc_locale_name,
+							LOCALE_NAME_MAX_LENGTH);
+		/*
+		 * If the lc_messages is already an IETF-standardized string, we have
+		 * a direct match with LOCALE_SNAME, e.g. en-US, en_US
+		 */
+		ret_val = GetLocaleInfoEx(wc_locale_name, LOCALE_SNAME, (LPWSTR)&buffer,
+								  LOCALE_NAME_MAX_LENGTH);
+		if (!ret_val)
+		{
+			/*
+			 * Search for a locale in the system that matches language and
+			 * county names.
+			 */
+			wchar_t	  *argv[3];
+
+			argv[0] = wc_locale_name;
+			argv[1] = buffer;
+			argv[2] = (wchar_t *) &ret_val;
+			EnumSystemLocalesEx(search_locale_enum, LOCALE_WINDOWS, (LPARAM) argv,
+								NULL);
+		}
+
+		if (ret_val)
+		{
+			/* Locale names use only ASCII, any conversion locale suffices. */
+			rc = wchar2char(iso_lc_messages, buffer, sizeof(iso_lc_messages),
+							NULL);
+		}
+#else							/* _MSC_VER < 1900 */
+		_locale_t	loct;
+
+		loct = _create_locale(LC_CTYPE, winlocname);
+		if (loct != NULL)
+		{
+			rc = wchar2char(iso_lc_messages, loct->locinfo->locale_name[LC_CTYPE],
+							sizeof(iso_lc_messages), NULL);
+			_free_locale(loct);
+		}
+#endif							/* _MSC_VER >= 1900 */
 
-		/* Locale names use only ASCII, any conversion locale suffices. */
-		rc = wchar2char(iso_lc_messages, loct->locinfo->locale_name[LC_CTYPE],
-						sizeof(iso_lc_messages), NULL);
-		_free_locale(loct);
 		if (rc == -1 || rc == sizeof(iso_lc_messages))
 			return NULL;
 
@@ -1029,7 +1158,7 @@ IsoLocaleName(const char *winlocname)
 			*hyphen = '_';
 		return iso_lc_messages;
 	}
-#endif							/* _MSC_VER */
+#endif							/* defined(_MSC_VER) */
 	return NULL;				/* Not supported on this version of msvc/mingw */
 }
 #endif							/* WIN32 && LC_MESSAGES */
