diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 2d15e78fd08441d7e9113ba4d594dba0135389c6..49edc51dbaca20e5f5eacd77450cade4309e3b2e 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -259,6 +259,21 @@ PGconn *PQconnectdbParams(const char **keywords, const char **values, int expand
          </listitem>
         </varlistentry>
 
+        <varlistentry id="libpq-connect-client-encoding" xreflabel="client_encoding">
+         <term><literal>client_encoding</literal></term>
+         <listitem>
+         <para>
+          This sets the <varname>client_encoding</varname>
+          configuration parameter for this connection.  In addition to
+          the values accepted by the corresponding server option, you
+          can use <literal>auto</literal> to determine the right
+          encoding from the current locale in the client
+          (<envar>LC_CTYPE</envar> environment variable on Unix
+          systems).
+         </para>
+         </listitem>
+        </varlistentry>
+
         <varlistentry id="libpq-connect-options" xreflabel="options">
          <term><literal>options</literal></term>
          <listitem>
@@ -6345,6 +6360,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       linkend="libpq-connect-connect-timeout"> connection parameter.
      </para>
     </listitem>
+
+    <listitem>
+     <para>
+      <indexterm>
+       <primary><envar>PGCLIENTENCODING</envar></primary>
+      </indexterm>
+      <envar>PGCLIENTENCODING</envar> behaves the same as the <xref
+      linkend="libpq-connect-client-encoding"> connection parameter.
+     </para>
+    </listitem>
    </itemizedlist>
   </para>
 
@@ -6378,17 +6403,6 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
      </para>
     </listitem>
 
-    <listitem>
-     <para>
-      <indexterm>
-       <primary><envar>PGCLIENTENCODING</envar></primary>
-      </indexterm>
-      <envar>PGCLIENTENCODING</envar> sets the default client character
-      set encoding.  (Equivalent to <literal>SET client_encoding TO
-      ...</literal>.)
-     </para>
-    </listitem>
-
     <listitem>
      <para>
       <indexterm>
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index ff60a72059ee17ea3c9050b076498837a559cce8..baefb578826c1ea0698c033ad082c9bd5ade7513 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -593,6 +593,17 @@ $ <userinput>psql "service=myservice sslmode=require"</userinput>
     privileges, server is not running on the targeted host, etc.),
     <application>psql</application> will return an error and terminate.
     </para>
+
+    <para>
+     If at least one of standard input or standard output are a
+     terminal, then <application>psql</application> sets the client
+     encoding to <quote>auto</quote>, which will detect the
+     appropriate client encoding from the locale settings
+     (<envar>LC_CTYPE</envar> environment variable on Unix systems).
+     If this doesn't work out as expected, the client encoding can be
+     overridden using the environment
+     variable <envar>PGCLIENTENCODING</envar>.
+    </para>
   </refsect2>
 
   <refsect2 id="R2-APP-PSQL-4">
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index d1268848d5b8bb550e860bdb2b209ed127eac0c1..d7cdcf64344ef70129588b39946f9069c06c371b 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -1487,7 +1487,7 @@ do_connect(char *dbname, char *user, char *host, char *port)
 
 	while (true)
 	{
-#define PARAMS_ARRAY_SIZE	7
+#define PARAMS_ARRAY_SIZE	8
 		const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
 		const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
 
@@ -1503,8 +1503,10 @@ do_connect(char *dbname, char *user, char *host, char *port)
 		values[4] = dbname;
 		keywords[5] = "fallback_application_name";
 		values[5] = pset.progname;
-		keywords[6] = NULL;
-		values[6] = NULL;
+		keywords[6] = "client_encoding";
+		values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
+		keywords[7] = NULL;
+		values[7] = NULL;
 
 		n_conn = PQconnectdbParams(keywords, values, true);
 
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
index 10713e9b15d6d5757410f75647caeaa363e51c1c..7b8078c21e4b0d22152f1d6d0fc3ae17897adbae 100644
--- a/src/bin/psql/startup.c
+++ b/src/bin/psql/startup.c
@@ -171,7 +171,7 @@ main(int argc, char *argv[])
 	/* loop until we have a password if requested by backend */
 	do
 	{
-#define PARAMS_ARRAY_SIZE	7
+#define PARAMS_ARRAY_SIZE	8
 		const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
 		const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
 
@@ -189,8 +189,10 @@ main(int argc, char *argv[])
 			"postgres" : options.dbname;
 		keywords[5] = "fallback_application_name";
 		values[5] = pset.progname;
-		keywords[6] = NULL;
-		values[6] = NULL;
+		keywords[6] = "client_encoding";
+		values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
+		keywords[7] = NULL;
+		values[7] = NULL;
 
 		new_pass = false;
 		pset.db = PQconnectdbParams(keywords, values, true);
diff --git a/src/interfaces/libpq/.gitignore b/src/interfaces/libpq/.gitignore
index 366adeb9080a49564b32f6a9d2dfcb0cd6dadf37..29024ae67ce1cec97f38746b641eb4d0b750fc89 100644
--- a/src/interfaces/libpq/.gitignore
+++ b/src/interfaces/libpq/.gitignore
@@ -1,4 +1,5 @@
 /exports.list
+/chklocale.c
 /crypt.c
 /getaddrinfo.c
 /inet_aton.c
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index f4111c4b766c629bdfb1c2ec8686d5d9257f36d0..18795446d5b93c1fb8f2f9085aaa297d8770f08b 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -35,7 +35,7 @@ OBJS=	fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
 	fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
 	libpq-events.o
 # libpgport C files we always use
-OBJS += inet_net_ntop.o noblock.o pgstrcasecmp.o thread.o
+OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o thread.o
 # libpgport C files that are needed if identified by configure
 OBJS += $(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
 # backend/libpq
@@ -88,7 +88,7 @@ backend_src = $(top_srcdir)/src/backend
 # For some libpgport modules, this only happens if configure decides 
 # the module is needed (see filter hack in OBJS, above).
 
-crypt.c getaddrinfo.c inet_aton.c inet_net_ntop.c noblock.c open.c pgsleep.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c: % : $(top_srcdir)/src/port/%
+chklocale.c crypt.c getaddrinfo.c inet_aton.c inet_net_ntop.c noblock.c open.c pgsleep.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c: % : $(top_srcdir)/src/port/%
 	rm -f $@ && $(LN_S) $< .
 
 ip.c md5.c: % : $(backend_src)/libpq/%
@@ -135,7 +135,7 @@ clean distclean: clean-lib
 # Might be left over from a Win32 client-only build
 	rm -f pg_config_paths.h
 	rm -f inet_net_ntop.c noblock.c pgstrcasecmp.c thread.c
-	rm -f crypt.c getaddrinfo.c inet_aton.c open.c snprintf.c strerror.c strlcpy.c win32error.c
+	rm -f chklocale.c crypt.c getaddrinfo.c inet_aton.c open.c snprintf.c strerror.c strlcpy.c win32error.c
 	rm -f pgsleep.c	
 	rm -f md5.c ip.c
 	rm -f encnames.c wchar.c
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index b8013ed42fcda4e5961d5ab77868e7c424c17b00..7766c7eabae425aabf9669ccae0542550e01fa1c 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -175,6 +175,9 @@ static const PQconninfoOption PQconninfoOptions[] = {
 	{"port", "PGPORT", DEF_PGPORT_STR, NULL,
 	"Database-Port", "", 6},
 
+	{"client_encoding", "PGCLIENTENCODING", NULL, NULL,
+	"Client-Encoding", "", 10},
+
 	/*
 	 * "tty" is no longer used either, but keep it present for backwards
 	 * compatibility.
@@ -270,9 +273,6 @@ static const PQEnvironmentOption EnvironmentOptions[] =
 	{
 		"PGTZ", "timezone"
 	},
-	{
-		"PGCLIENTENCODING", "client_encoding"
-	},
 	/* internal performance-related settings */
 	{
 		"PGGEQO", "geqo"
@@ -612,6 +612,8 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
 	conn->pgpass = tmp ? strdup(tmp) : NULL;
 	tmp = conninfo_getval(connOptions, "connect_timeout");
 	conn->connect_timeout = tmp ? strdup(tmp) : NULL;
+	tmp = conninfo_getval(connOptions, "client_encoding");
+	conn->client_encoding_initial = tmp ? strdup(tmp) : NULL;
 	tmp = conninfo_getval(connOptions, "keepalives");
 	conn->keepalives = tmp ? strdup(tmp) : NULL;
 	tmp = conninfo_getval(connOptions, "keepalives_idle");
@@ -786,6 +788,16 @@ connectOptions2(PGconn *conn)
 	else
 		conn->sslmode = strdup(DefaultSSLMode);
 
+	/*
+	 * Resolve special "auto" client_encoding from the locale
+	 */
+	if (conn->client_encoding_initial &&
+		strcmp(conn->client_encoding_initial, "auto") == 0)
+	{
+		free(conn->client_encoding_initial);
+		conn->client_encoding_initial = strdup(pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true)));
+	}
+
 	/*
 	 * Only if we get this far is it appropriate to try to connect. (We need a
 	 * state flag, rather than just the boolean result of this function, in
@@ -2508,7 +2520,7 @@ keep_going:						/* We will come back to here until there is
 				if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
 				{
 					conn->status = CONNECTION_SETENV;
-					conn->setenv_state = SETENV_STATE_OPTION_SEND;
+					conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_SEND;
 					conn->next_eo = EnvironmentOptions;
 					return PGRES_POLLING_WRITING;
 				}
@@ -4661,6 +4673,10 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
 	if (!encoding)
 		return -1;
 
+	/* Resolve special "auto" value from the locale */
+	if (strcmp(encoding, "auto") == 0)
+		encoding = pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true));
+
 	/* check query buffer overflow */
 	if (sizeof(qbuf) < (sizeof(query) + strlen(encoding)))
 		return -1;
diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c
index 058a25b8033ebf656e433b651d86a989599e3a99..05357de1c74f81d96e507e71a78274e9f4cc3ef7 100644
--- a/src/interfaces/libpq/fe-protocol2.c
+++ b/src/interfaces/libpq/fe-protocol2.c
@@ -58,6 +58,7 @@ pqSetenvPoll(PGconn *conn)
 	switch (conn->setenv_state)
 	{
 			/* These are reading states */
+		case SETENV_STATE_CLIENT_ENCODING_WAIT:
 		case SETENV_STATE_OPTION_WAIT:
 		case SETENV_STATE_QUERY1_WAIT:
 		case SETENV_STATE_QUERY2_WAIT:
@@ -74,6 +75,7 @@ pqSetenvPoll(PGconn *conn)
 			}
 
 			/* These are writing states, so we just proceed. */
+		case SETENV_STATE_CLIENT_ENCODING_SEND:
 		case SETENV_STATE_OPTION_SEND:
 		case SETENV_STATE_QUERY1_SEND:
 		case SETENV_STATE_QUERY2_SEND:
@@ -98,6 +100,39 @@ pqSetenvPoll(PGconn *conn)
 	{
 		switch (conn->setenv_state)
 		{
+			/*
+			 * The _CLIENT_ENCODING_SEND code is slightly different
+			 * from _OPTION_SEND below (e.g., no getenv() call), which
+			 * is why a different state is used.
+			 */
+			case SETENV_STATE_CLIENT_ENCODING_SEND:
+				{
+					char		setQuery[100];	/* note length limit in
+												 * sprintf below */
+					const char *val = conn->client_encoding_initial;
+
+					if (val)
+					{
+						if (pg_strcasecmp(val, "default") == 0)
+							sprintf(setQuery, "SET client_encoding = DEFAULT");
+						else
+							sprintf(setQuery, "SET client_encoding = '%.60s'",
+									val);
+#ifdef CONNECTDEBUG
+						fprintf(stderr,
+								"Sending client_encoding with %s\n",
+								setQuery);
+#endif
+						if (!PQsendQuery(conn, setQuery))
+							goto error_return;
+
+						conn->setenv_state = SETENV_STATE_CLIENT_ENCODING_WAIT;
+					}
+					else
+						conn->setenv_state = SETENV_STATE_OPTION_SEND;
+					break;
+				}
+
 			case SETENV_STATE_OPTION_SEND:
 				{
 					/*
@@ -142,6 +177,31 @@ pqSetenvPoll(PGconn *conn)
 					break;
 				}
 
+			case SETENV_STATE_CLIENT_ENCODING_WAIT:
+				{
+					if (PQisBusy(conn))
+						return PGRES_POLLING_READING;
+
+					res = PQgetResult(conn);
+
+					if (res)
+					{
+						if (PQresultStatus(res) != PGRES_COMMAND_OK)
+						{
+							PQclear(res);
+							goto error_return;
+						}
+						PQclear(res);
+						/* Keep reading until PQgetResult returns NULL */
+					}
+					else
+					{
+						/* Query finished, so send the next option */
+						conn->setenv_state = SETENV_STATE_OPTION_SEND;
+					}
+					break;
+				}
+
 			case SETENV_STATE_OPTION_WAIT:
 				{
 					if (PQisBusy(conn))
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 2a8dbdfd3aa5edfc960db19dd0aa3c4c83b9deef..cf0b91a9bc1b2d5cbc84def4526e92958fe26a33 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -1933,6 +1933,9 @@ build_startup_packet(const PGconn *conn, char *packet,
 			ADD_STARTUP_OPTION("application_name", val);
 	}
 
+	if (conn->client_encoding_initial && conn->client_encoding_initial[0])
+		ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial);
+
 	/* Add any environment-driven GUC settings needed */
 	for (next_eo = options; next_eo->envName; next_eo++)
 	{
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index e9a2b718d33d762691e95f099aca4af9308a46f0..25c779acd7ef2c0a29f8e55885f3f478dcaafe37 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -235,6 +235,8 @@ typedef enum
 /* (this is used only for 2.0-protocol connections) */
 typedef enum
 {
+	SETENV_STATE_CLIENT_ENCODING_SEND,	/* About to send an Environment Option */
+	SETENV_STATE_CLIENT_ENCODING_WAIT,	/* Waiting for above send to complete */
 	SETENV_STATE_OPTION_SEND,	/* About to send an Environment Option */
 	SETENV_STATE_OPTION_WAIT,	/* Waiting for above send to complete */
 	SETENV_STATE_QUERY1_SEND,	/* About to send a status query */
@@ -293,6 +295,7 @@ struct pg_conn
 	char	   *pgtty;			/* tty on which the backend messages is
 								 * displayed (OBSOLETE, NOT USED) */
 	char	   *connect_timeout;	/* connection timeout (numeric string) */
+	char	   *client_encoding_initial; /* encoding to use */
 	char	   *pgoptions;		/* options to start the backend with */
 	char	   *appname;		/* application name */
 	char	   *fbappname;		/* fallback application name */