*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 3721,3726 **** add_placeholder_variable(const char *name, int elevel)
--- 3721,3735 ----
  	gen->vartype = PGC_STRING;
  
  	/*
+ 	 * Any change of custom status variable is forwarded back to client.
+ 	 * It is implemented via GUC_REPORT flag.
+ 	 */
+ 	if (strncmp(name, "status.", 7) == 0)
+ 	{
+ 		gen->flags |= GUC_REPORT;
+ 	}
+ 
+ 	/*
  	 * The char* is allocated at the end of the struct since we have no
  	 * 'static' place to point to.	Note that the current value, as well as
  	 * the boot and reset values, start out NULL.
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
***************
*** 1092,1098 **** exec_command(const char *cmd,
  				free(opt);
  			}
  
! 			if (!SetVariable(pset.vars, opt0, newval))
  			{
  				psql_error("\\%s: error while setting variable\n", cmd);
  				success = false;
--- 1092,1098 ----
  				free(opt);
  			}
  
! 			if (!SetVar(pset.vars, opt0, newval))
  			{
  				psql_error("\\%s: error while setting variable\n", cmd);
  				success = false;
***************
*** 1618,1623 **** do_connect(char *dbname, char *user, char *host, char *port)
--- 1618,1625 ----
  	 * connection-dependent variables.
  	 */
  	PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
+ 	PQsetStatusVariableReceiver(n_conn, StatusVariableReceiver);
+ 
  	pset.db = n_conn;
  	SyncVariables();
  	connection_warnings(false); /* Must be after SyncVariables */
***************
*** 1762,1767 **** checkWin32Codepage(void)
--- 1764,1771 ----
  void
  SyncVariables(void)
  {
+ 	const char **varnames;
+ 
  	/* get stuff from connection */
  	pset.encoding = PQclientEncoding(pset.db);
  	pset.popt.topt.encoding = pset.encoding;
***************
*** 1775,1780 **** SyncVariables(void)
--- 1779,1802 ----
  
  	/* send stuff to it, too */
  	PQsetErrorVerbosity(pset.db, pset.verbosity);
+ 
+ 	varnames = GetVarnames(pset.vars);
+ 
+ 	/* sync status variables */
+ 	if (varnames != NULL)
+ 	{
+ 		int i;
+ 
+ 		for (i = 0; varnames[i]; i++)
+ 		{
+ 			if (is_custom_status_variable(varnames[i]))
+ 			{
+ 				ForwardStatusVar(varnames[i], GetVariable(pset.vars, varnames[i]));
+ 			}
+ 		}
+ 	}
+ 
+ 	free(varnames);
  }
  
  /*
*** a/src/bin/psql/common.c
--- b/src/bin/psql/common.c
***************
*** 183,189 **** NoticeProcessor(void *arg, const char *message)
  	psql_error("%s", message);
  }
  
! 
  
  /*
   * Code to support query cancellation
--- 183,199 ----
  	psql_error("%s", message);
  }
  
! /*
!  * for custom status variables
!  */
! void
! StatusVariableReceiver(const char *varname, const char *value)
! {
! 	if (!SetVariable(pset.vars, varname, value))
! 	{
! 		psql_error("cannot set custom status variable \"%s\"\n", varname);
! 	}
! }
  
  /*
   * Code to support query cancellation
***************
*** 1668,1670 **** expand_tilde(char **filename)
--- 1678,1740 ----
  
  	return *filename;
  }
+ 
+ /*
+  * forward change of some status variable to server
+  */
+ bool
+ ForwardStatusVar(const char *name, const char *value)
+ {
+ 	char *escaped_value;
+ 	PQExpBufferData		query_buffer;
+ 	PGresult *res;
+ 
+ 	escaped_value = PQescapeLiteral(pset.db, value, strlen(value));
+ 	if (escaped_value == NULL)
+ 	{
+ 		const char *error = PQerrorMessage(pset.db);
+ 
+ 		psql_error("%s", error);
+ 
+ 		return false;
+ 	}
+ 
+ 	initPQExpBuffer(&query_buffer);
+ 
+ 	appendPQExpBuffer(&query_buffer, "SET %s = %s",
+ 								name,
+ 								escaped_value);
+ 	PQfreemem(escaped_value);
+ 
+ 	res = PSQLexec(query_buffer.data, false);
+ 
+ 	termPQExpBuffer(&query_buffer);
+ 
+ 	if (res != NULL)
+ 	{
+ 		PQclear(res);
+ 
+ 		return true;
+ 	}
+ 	else
+ 		return false;
+ }
+ 
+ /*
+  * switch handling of variables between status variables (server) and
+  * other variables (local).
+  */
+ bool
+ SetVar(VariableSpace space, const char *name, const char *value)
+ {
+ 	if (is_custom_status_variable(name) && pset.db)
+ 		return ForwardStatusVar(name, value);
+ 
+ 	if (!SetVariable(pset.vars, name, value))
+ 	{
+ 		psql_error("error while setting variable\n");
+ 		return false;
+ 	}
+ 
+ 	return true;
+ }
*** a/src/bin/psql/common.h
--- b/src/bin/psql/common.h
***************
*** 12,17 ****
--- 12,19 ----
  #include <setjmp.h>
  #include "libpq-fe.h"
  
+ #include "variables.h"
+ 
  #ifdef USE_ASSERT_CHECKING
  #include <assert.h>
  #define psql_assert(p) assert(p)
***************
*** 39,44 **** psql_error(const char *fmt,...)
--- 41,47 ----
  __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
  
  extern void NoticeProcessor(void *arg, const char *message);
+ extern void StatusVariableReceiver(const char *varname, const char *value);
  
  extern volatile bool sigint_interrupt_enabled;
  
***************
*** 63,66 **** extern const char *session_username(void);
--- 66,75 ----
  
  extern char *expand_tilde(char **filename);
  
+ extern bool SetVar(VariableSpace space, const char *name, const char *value);
+ extern const char *GetVar(VariableSpace space, const char *name, bool *is_error);
+ 
+ extern bool ForwardStatusVar(const char *name, const char *value);
+ 
+ 
  #endif   /* COMMON_H */
*** a/src/bin/psql/psqlscan.l
--- b/src/bin/psql/psqlscan.l
***************
*** 389,395 **** realfail2		({integer}|{decimal})[Ee][-+]
  param			\${integer}
  
  /* psql-specific: characters allowed in variable names */
! variable_char	[A-Za-z\200-\377_0-9]
  
  other			.
  
--- 389,395 ----
  param			\${integer}
  
  /* psql-specific: characters allowed in variable names */
! variable_char	[A-Za-z\200-\377_0-9.]
  
  other			.
  
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
***************
*** 250,255 **** main(int argc, char *argv[])
--- 250,256 ----
  	}
  
  	PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
+ 	PQsetStatusVariableReceiver(pset.db, StatusVariableReceiver);
  
  	SyncVariables();
  
***************
*** 524,530 **** parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
  					else
  					{
  						*equal_loc = '\0';
! 						if (!SetVariable(pset.vars, value, equal_loc + 1))
  						{
  							fprintf(stderr, _("%s: could not set variable \"%s\"\n"),
  									pset.progname, value);
--- 525,531 ----
  					else
  					{
  						*equal_loc = '\0';
! 						if (!SetVar(pset.vars, value, equal_loc + 1))
  						{
  							fprintf(stderr, _("%s: could not set variable \"%s\"\n"),
  									pset.progname, value);
*** a/src/bin/psql/variables.c
--- b/src/bin/psql/variables.c
***************
*** 30,36 **** valid_variable_name(const char *name)
  	while (*ptr)
  	{
  		if (IS_HIGHBIT_SET(*ptr) ||
! 			strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
  				   "_0123456789", *ptr) != NULL)
  			ptr++;
  		else
--- 30,36 ----
  	while (*ptr)
  	{
  		if (IS_HIGHBIT_SET(*ptr) ||
! 			strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "."
  				   "_0123456789", *ptr) != NULL)
  			ptr++;
  		else
***************
*** 41,46 **** valid_variable_name(const char *name)
--- 41,55 ----
  }
  
  /*
+  * returns true, when variable has prefix for custom status variables
+  */
+ bool
+ is_custom_status_variable(const char *varname)
+ {
+ 	return strncmp(varname, "status.", 7) == 0;
+ }
+ 
+ /*
   * A "variable space" is represented by an otherwise-unused struct _variable
   * that serves as list header.
   */
***************
*** 296,298 **** DeleteVariable(VariableSpace space, const char *name)
--- 305,342 ----
  
  	return true;
  }
+ 
+ 
+ const char **
+ GetVarnames(VariableSpace space)
+ {
+ 	int	count = 0;
+ 	int			i;
+ 
+ 	struct _variable *current,
+ 			   *previous;
+ 	char **result;
+ 
+ 	if (!space)
+ 		return NULL;
+ 
+ 	for (previous = space, current = space->next;
+ 		 current;
+ 		 previous = current, current = current->next)
+ 	{
+ 		count++;
+ 	}
+ 
+ 	result = pg_malloc(sizeof(char *) * (count + 1));
+ 
+ 	for (previous = space, current = space->next, i = 0;
+ 		 current;
+ 		 previous = current, current = current->next, i++)
+ 	{
+ 		result[i] = current->name;
+ 	}
+ 
+ 	result[i] = NULL;
+ 
+ 	return result;
+ }
*** a/src/bin/psql/variables.h
--- b/src/bin/psql/variables.h
***************
*** 52,56 **** bool		SetVariable(VariableSpace space, const char *name, const char *value);
--- 52,59 ----
  bool		SetVariableAssignHook(VariableSpace space, const char *name, VariableAssignHook hook);
  bool		SetVariableBool(VariableSpace space, const char *name);
  bool		DeleteVariable(VariableSpace space, const char *name);
+ bool		is_custom_status_variable(const char *varname);
+ const char **GetVarnames(VariableSpace space);
+ 
  
  #endif   /* VARIABLES_H */
*** a/src/interfaces/libpq/exports.txt
--- b/src/interfaces/libpq/exports.txt
***************
*** 161,163 **** PQping                    158
--- 161,164 ----
  PQpingParams              159
  PQlibVersion              160
  PQsetSingleRowMode        161
+ PQsetStatusVariableReceiver	162
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
***************
*** 325,330 **** static PQconninfoOption *conninfo_find(PQconninfoOption *connOptions,
--- 325,331 ----
  			  const char *keyword);
  static void defaultNoticeReceiver(void *arg, const PGresult *res);
  static void defaultNoticeProcessor(void *arg, const char *message);
+ static void defaultStatusVariableReceiver(const char *varname, const char *value);
  static int parseServiceInfo(PQconninfoOption *options,
  				 PQExpBuffer errorMessage);
  static int parseServiceFile(const char *serviceFile,
***************
*** 2712,2717 **** makeEmptyPGconn(void)
--- 2713,2719 ----
  	/* install default notice hooks */
  	conn->noticeHooks.noticeRec = defaultNoticeReceiver;
  	conn->noticeHooks.noticeProc = defaultNoticeProcessor;
+ 	conn->statusVariableReceiverProc = defaultStatusVariableReceiver;
  
  	conn->status = CONNECTION_BAD;
  	conn->asyncStatus = PGASYNC_IDLE;
***************
*** 5411,5416 **** defaultNoticeProcessor(void *arg, const char *message)
--- 5413,5446 ----
  	fprintf(stderr, "%s", message);
  }
  
+ PQstatusVariableReceiver
+ PQsetStatusVariableReceiver(PGconn *conn, PQstatusVariableReceiver proc)
+ {
+ 	PQstatusVariableReceiver old;
+ 
+ 	if (conn == NULL)
+ 		return NULL;
+ 
+ 	old = conn->statusVariableReceiverProc;
+ 	if (proc)
+ 	{
+ 		conn->statusVariableReceiverProc = proc;
+ 	}
+ 	return old;
+ }
+ 
+ /*
+  * The default custom status variable just prints the
+  * name and value on stderr. Applications can override this if they
+  * want use own processing of custom status variables.
+  */
+ static void
+ defaultStatusVariableReceiver(const char *varname, const char *value)
+ 
+ {
+ 	fprintf(stderr, "received %s=\"%s\"\n", varname, value);
+ }
+ 
  /*
   * returns a pointer to the next token or NULL if the current
   * token doesn't match
*** a/src/interfaces/libpq/fe-exec.c
--- b/src/interfaces/libpq/fe-exec.c
***************
*** 910,915 **** pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
--- 910,920 ----
  	pgParameterStatus *pstatus;
  	pgParameterStatus *prev;
  
+ 	/* forward custom status variables to own callback processor */
+ 	if (strncmp(name, "status.", 7) == 0)
+ 		(*conn->statusVariableReceiverProc) (name, value);
+ 
+ 
  	if (conn->Pfdebug)
  		fprintf(conn->Pfdebug, "pqSaveParameterStatus: '%s' = '%s'\n",
  				name, value);
*** a/src/interfaces/libpq/libpq-fe.h
--- b/src/interfaces/libpq/libpq-fe.h
***************
*** 155,160 **** typedef struct pgNotify
--- 155,163 ----
  typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res);
  typedef void (*PQnoticeProcessor) (void *arg, const char *message);
  
+ /* Function types for custom status variables handling callbasks */
+ typedef void (*PQstatusVariableReceiver) (const char *varname, const char *value);
+ 
  /* Print options for PQprint() */
  typedef char pqbool;
  
***************
*** 335,340 **** extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn,
--- 338,347 ----
  					 PQnoticeProcessor proc,
  					 void *arg);
  
+ /* Override custom status variable handling routine */
+ extern PQstatusVariableReceiver PQsetStatusVariableReceiver(PGconn *conn,
+ 					    PQstatusVariableReceiver proc);
+ 
  /*
   *	   Used to set callback that prevents concurrent access to
   *	   non-thread safe functions that libpq needs.
*** a/src/interfaces/libpq/libpq-int.h
--- b/src/interfaces/libpq/libpq-int.h
***************
*** 458,463 **** struct pg_conn
--- 458,466 ----
  
  	/* Buffer for receiving various parts of messages */
  	PQExpBufferData workBuffer; /* expansible string */
+ 
+ 	/* callback for processing of custom status variables */
+ 	PQstatusVariableReceiver statusVariableReceiverProc;
  };
  
  /* PGcancel stores all data necessary to cancel a connection. A copy of this
