diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index 1e67da983c..0aaa10743c 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -17,6 +17,7 @@
 #include "catalog/pg_user_mapping.h"
 #include "commands/defrem.h"
 #include "funcapi.h"
+#include "lib/stringinfo.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "pgstat.h"
@@ -350,7 +351,9 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
 	{
 		const char **keywords;
 		const char **values;
+		StringInfo buf;
 		int			n;
+		int			i;
 
 		/*
 		 * Construct connection params from generic options of ForeignServer
@@ -362,6 +365,7 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
 		n = list_length(server->options) + list_length(user->options) + 4;
 		keywords = (const char **) palloc(n * sizeof(char *));
 		values = (const char **) palloc(n * sizeof(char *));
+		buf = makeStringInfo();
 
 		n = 0;
 		n += ExtractConnectionOptions(server->options,
@@ -385,6 +389,37 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
 			n++;
 		}
 
+		/*
+		 * Search application_name and replace it if found.
+		 *
+		 * We search paramters from the end because the later
+		 * one have higher priority.  See also the above comment.
+		 */
+		for (i = n - 1; i >= 0; i--)
+		{
+			if (strcmp(keywords[i], "application_name") == 0)
+			{
+				parse_pgfdw_appname(buf, values[i]);
+
+				/* Use the string and break if it is valid */
+				if (strcmp(buf->data, "") != 0)
+				{
+					values[i] = buf->data;
+					break;
+				}
+
+				/*
+				 * The parsing result became an empty string,
+				 * and that means other "application_name" will be used
+				 * for connecting to the remote server.
+				 * So we must set values[i] to an empty string
+				 * and search the array again. buf is reset for reuse.
+				 */
+				values[i] = "";
+				resetStringInfo(buf);
+			}
+		}
+
 		/* Use "postgres_fdw" as fallback_application_name */
 		keywords[n] = "fallback_application_name";
 		values[n] = "postgres_fdw";
@@ -456,6 +491,8 @@ connect_pg_server(ForeignServer *server, UserMapping *user)
 
 		pfree(keywords);
 		pfree(values);
+		pfree(buf->data);
+		pfree(buf);
 	}
 	PG_CATCH();
 	{
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index c7b7db8065..aa9673e398 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -10761,3 +10761,33 @@ ERROR:  invalid value for integer option "fetch_size": 100$%$#$#
 CREATE FOREIGN TABLE inv_bsz (c1 int )
 	SERVER loopback OPTIONS (batch_size '100$%$#$#');
 ERROR:  invalid value for integer option "batch_size": 100$%$#$#
+-- ===================================================================
+-- test postgres_fdw.application_name GUC
+-- ===================================================================
+SET debug_discard_caches TO 0;
+-- Some escapes can be used for this GUC.
+SET postgres_fdw.application_name TO '%a%u%d%p%%';
+-- All escape candidates depend on the runtime environment
+-- and it causes some fails for this tests.
+-- Hence we just count number of rows here. It returns a row if works well.
+SELECT 1 FROM postgres_fdw_disconnect_all();
+ ?column? 
+----------
+        1
+(1 row)
+
+SELECT 1 FROM ft6 LIMIT 1;
+ ?column? 
+----------
+        1
+(1 row)
+
+SELECT COUNT(*) FROM pg_stat_activity WHERE application_name = current_setting('application_name') || current_user || current_database() || pg_backend_pid() || '%';
+ count 
+-------
+     1
+(1 row)
+
+--Clean up
+RESET postgres_fdw.application_name;
+RESET debug_discard_caches;
diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c
index 5bb1af4084..a5dac259c1 100644
--- a/contrib/postgres_fdw/option.c
+++ b/contrib/postgres_fdw/option.c
@@ -18,6 +18,9 @@
 #include "catalog/pg_user_mapping.h"
 #include "commands/defrem.h"
 #include "commands/extension.h"
+#include "common/string.h"
+#include "lib/stringinfo.h"
+#include "libpq/libpq-be.h"
 #include "postgres_fdw.h"
 #include "utils/builtins.h"
 #include "utils/guc.h"
@@ -443,6 +446,125 @@ ExtractExtensionList(const char *extensionsString, bool warnOnMissing)
 	return extensionOids;
 }
 
+/*
+ * parse postgres_fdw.application_name and set escaped string.
+ * This function is almost same as log_line_prefix(), but
+ * accepted escape sequence is different.
+ *
+ * Note that argument buf must be initialized.
+ */
+void
+parse_pgfdw_appname(StringInfo buf, const char *name)
+{
+	int			padding;
+	const char *p;
+
+	for(p = name; *p != '\0'; p++)
+	{
+		if (*p != '%')
+		{
+			/* literal char, just copy */
+			appendStringInfoChar(buf, *p);
+			continue;
+		}
+
+		/* must be a '%', so skip to the next char */
+		p++;
+		if (*p == '\0')
+			break;				/* format error - ignore it */
+		else if (*p == '%')
+		{
+			/* string contains %% */
+			appendStringInfoChar(buf, '%');
+			continue;
+		}
+
+		/*
+		 * Process any formatting which may exist after the '%'.
+		 *
+		 * For other notes, see log_line_prefix().
+		 */
+		if (*p > '9')
+			padding = 0;
+		else if (*p == '-' ? isdigit(p[1]) : isdigit(p[0]))
+		{
+			char *endptr;
+			padding = strtol(p, &endptr, 10);
+			if (p == endptr || *endptr == '\0')
+				break;
+			p = endptr;
+		}
+		else
+			if (*p == '-')
+			{
+				p++;
+				padding = -1;
+			}
+			else
+				padding = 0;
+
+
+		/* process the option */
+		switch (*p)
+		{
+			case 'a':
+				if (MyProcPort)
+				{
+					const char *appname = application_name;
+
+					if (appname == NULL || *appname == '\0')
+						appname = "[unknown]";
+					if (padding != 0)
+						appendStringInfo(buf, "%*s", padding, appname);
+					else
+						appendStringInfoString(buf, appname);
+				}
+				else if (padding != 0)
+					appendStringInfoSpaces(buf, abs(padding));
+				break;
+			case 'u':
+				if (MyProcPort)
+				{
+					const char *username = MyProcPort->user_name;
+
+					if (username == NULL || *username == '\0')
+						username = "[unknown]";
+					if (padding != 0)
+						appendStringInfo(buf, "%*s", padding, username);
+					else
+						appendStringInfoString(buf, username);
+				}
+				else if (padding != 0)
+					appendStringInfoSpaces(buf, abs(padding));
+				break;
+			case 'd':
+				if (MyProcPort)
+				{
+					const char *dbname = MyProcPort->database_name;
+
+					if (dbname == NULL || *dbname == '\0')
+						dbname =  "[unknown]";
+					if (padding != 0)
+						appendStringInfo(buf, "%*s", padding, dbname);
+					else
+						appendStringInfoString(buf, dbname);
+				}
+				else if (padding != 0)
+					appendStringInfoSpaces(buf, abs(padding));
+				break;
+			case 'p':
+				if (padding != 0)
+					appendStringInfo(buf, "%*d", padding, MyProcPid);
+				else
+					appendStringInfo(buf, "%d", MyProcPid);
+				break;
+			default:
+				/* format error - ignore it */
+				break;
+		}
+	}
+}
+
 /*
  * Module load callback
  */
diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h
index 90b72e9ec5..2f036391f0 100644
--- a/contrib/postgres_fdw/postgres_fdw.h
+++ b/contrib/postgres_fdw/postgres_fdw.h
@@ -158,6 +158,7 @@ extern int	ExtractConnectionOptions(List *defelems,
 									 const char **values);
 extern List *ExtractExtensionList(const char *extensionsString,
 								  bool warnOnMissing);
+extern void parse_pgfdw_appname(StringInfo buf, const char *name);
 extern char *pgfdw_application_name;
 
 /* in deparse.c */
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 38f4a7837f..c6c10996a0 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -3422,3 +3422,20 @@ CREATE FOREIGN TABLE inv_fsz (c1 int )
 -- Invalid batch_size option
 CREATE FOREIGN TABLE inv_bsz (c1 int )
 	SERVER loopback OPTIONS (batch_size '100$%$#$#');
+
+-- ===================================================================
+-- test postgres_fdw.application_name GUC
+-- ===================================================================
+SET debug_discard_caches TO 0;
+-- Some escapes can be used for this GUC.
+SET postgres_fdw.application_name TO '%a%u%d%p%%';
+-- All escape candidates depend on the runtime environment
+-- and it causes some fails for this tests.
+-- Hence we just count number of rows here. It returns a row if works well.
+SELECT 1 FROM postgres_fdw_disconnect_all();
+SELECT 1 FROM ft6 LIMIT 1;
+SELECT COUNT(*) FROM pg_stat_activity WHERE application_name = current_setting('application_name') || current_user || current_database() || pg_backend_pid() || '%';
+
+--Clean up
+RESET postgres_fdw.application_name;
+RESET debug_discard_caches;
diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml
index 41c952fbe3..cc963b0a25 100644
--- a/doc/src/sgml/postgres-fdw.sgml
+++ b/doc/src/sgml/postgres-fdw.sgml
@@ -180,6 +180,10 @@ OPTIONS (ADD password_required 'false');
     relationship granted by authentication modes like <literal>peer</literal>
     or <literal>ident</literal> authentication.
    </para>
+   <para>
+    You can use escape sequences for <literal>application_name</literal> even if
+    it is set as a connection option. Please refer the later section.
+   </para>
   </sect3>
 
   <sect3>
@@ -920,7 +924,7 @@ postgres=# SELECT postgres_fdw_disconnect_all();
   <title>Configuration Parameters</title>
 
   <variablelist>
-   <varlistentry>
+   <varlistentry id="guc-pgfdw-application-name" xreflabel="pgfdw_application_name">
     <term>
      <varname>postgres_fdw.application_name</varname> (<type>string</type>)
      <indexterm>
@@ -936,6 +940,53 @@ postgres=# SELECT postgres_fdw_disconnect_all();
       Note that change of this parameter doesn't affect any existing
       connections until they are re-established.
      </para>
+
+     <para>
+      Same as <xref linkend="guc-log-line-prefix"/>, this is a
+      <function>printf</function>-style string. Accepted escapes are
+      bit different from <xref linkend="guc-log-line-prefix"/>,
+      but padding can be used like as it.
+     </para>
+
+     <informaltable>
+      <tgroup cols="2">
+       <thead>
+        <row>
+         <entry>Escape</entry>
+         <entry>Effect</entry>
+        </row>
+       </thead>
+       <tbody>
+        <row>
+         <entry><literal>%a</literal></entry>
+         <entry>Application name</entry>
+        </row>
+        <row>
+         <entry><literal>%u</literal></entry>
+         <entry>Local user name</entry>
+        </row>
+        <row>
+         <entry><literal>%d</literal></entry>
+         <entry>Local database name</entry>
+        </row>
+        <row>
+         <entry><literal>%p</literal></entry>
+         <entry>Local backend process ID</entry>
+        </row>
+        <row>
+         <entry><literal>%%</literal></entry>
+         <entry>Liteal %</entry>
+        </row>
+       </tbody>
+      </tgroup>
+     </informaltable>
+
+     <para>
+     Note that if embedded strings have Non-ASCII,
+     these characters will be replaced with the question marks (<literal>?</literal>).
+     This limitation is caused by <literal>application_name</literal>.
+     </para>
+
     </listitem>
    </varlistentry>
   </variablelist>
