diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index a37e6b6..1187c9b 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -629,6 +629,16 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
      </entry>
     </row>
     <row>
+     <entry><structfield>backend_xid</structfield></entry>
+     <entry><type>xid</type></entry>
+     <entry>Toplevel transaction identifier of this backend, if any.</entry>
+    </row>
+    <row>
+     <entry><structfield>backend_xmin</structfield></entry>
+     <entry><type>xid</type></entry>
+     <entry>The current backend's <literal>xmin</> horizon.</entry>
+    </row>
+    <row>
      <entry><structfield>query</></entry>
      <entry><type>text</></entry>
      <entry>Text of this backend's most recent query. If
@@ -1484,6 +1494,12 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
      </entry>
     </row>
     <row>
+     <entry><structfield>backend_xid</structfield></entry>
+     <entry><type>xid</type></entry>
+     <entry>This standby's <literal>xmin</> horizon reported
+     by <xref linkend="guc-hot-standby-feedback">.</entry>
+    </row>
+    <row>
      <entry><structfield>state</></entry>
      <entry><type>text</></entry>
      <entry>Current WAL sender state</entry>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index a7c6a4e..04dfbb0 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -586,6 +586,8 @@ CREATE VIEW pg_stat_activity AS
             S.state_change,
             S.waiting,
             S.state,
+            S.backend_xid,
+            s.backend_xmin,
             S.query
     FROM pg_database D, pg_stat_get_activity(NULL) AS S, pg_authid U
     WHERE S.datid = D.oid AND
@@ -601,6 +603,7 @@ CREATE VIEW pg_stat_replication AS
             S.client_hostname,
             S.client_port,
             S.backend_start,
+            S.backend_xmin,
             W.state,
             W.sent_location,
             W.write_location,
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 305d126..c8285b8 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -48,12 +48,14 @@
 #include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
+#include "storage/proc.h"
 #include "storage/backendid.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
 #include "storage/pg_shmem.h"
 #include "storage/procsignal.h"
+#include "storage/sinvaladt.h"
 #include "utils/ascii.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
@@ -213,7 +215,7 @@ typedef struct TwoPhasePgStatRecord
  */
 static MemoryContext pgStatLocalContext = NULL;
 static HTAB *pgStatDBHash = NULL;
-static PgBackendStatus *localBackendStatusTable = NULL;
+static LocalPgBackendStatus *localBackendStatusTable = NULL;
 static int	localNumBackends = 0;
 
 /*
@@ -2306,6 +2308,28 @@ pgstat_fetch_stat_beentry(int beid)
 	if (beid < 1 || beid > localNumBackends)
 		return NULL;
 
+	return &localBackendStatusTable[beid - 1].backendStatus;
+}
+
+
+/* ----------
+ * pgstat_fetch_stat_local_beentry() -
+ *
+ *  Like pgstat_fetch_stat_beentry() but with local addtions (like xid and
+ *  xmin values of the backend)
+ *
+ *	NB: caller is responsible for a check if the user is permitted to see
+ *	this info (especially the querystring).
+ * ----------
+ */
+LocalPgBackendStatus *
+pgstat_fetch_stat_local_beentry(int beid)
+{
+	pgstat_read_current_status();
+
+	if (beid < 1 || beid > localNumBackends)
+		return NULL;
+
 	return &localBackendStatusTable[beid - 1];
 }
 
@@ -2783,8 +2807,8 @@ static void
 pgstat_read_current_status(void)
 {
 	volatile PgBackendStatus *beentry;
-	PgBackendStatus *localtable;
-	PgBackendStatus *localentry;
+	LocalPgBackendStatus *localtable;
+	LocalPgBackendStatus *localentry;
 	char	   *localappname,
 			   *localactivity;
 	int			i;
@@ -2795,9 +2819,9 @@ pgstat_read_current_status(void)
 
 	pgstat_setup_memcxt();
 
-	localtable = (PgBackendStatus *)
+	localtable = (LocalPgBackendStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(PgBackendStatus) * MaxBackends);
+						   sizeof(LocalPgBackendStatus) * MaxBackends);
 	localappname = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
 						   NAMEDATALEN * MaxBackends);
@@ -2821,19 +2845,19 @@ pgstat_read_current_status(void)
 		{
 			int			save_changecount = beentry->st_changecount;
 
-			localentry->st_procpid = beentry->st_procpid;
-			if (localentry->st_procpid > 0)
+			localentry->backendStatus.st_procpid = beentry->st_procpid;
+			if (localentry->backendStatus.st_procpid > 0)
 			{
-				memcpy(localentry, (char *) beentry, sizeof(PgBackendStatus));
+				memcpy(&localentry->backendStatus, (char *) beentry, sizeof(PgBackendStatus));
 
 				/*
 				 * strcpy is safe even if the string is modified concurrently,
 				 * because there's always a \0 at the end of the buffer.
 				 */
 				strcpy(localappname, (char *) beentry->st_appname);
-				localentry->st_appname = localappname;
+				localentry->backendStatus.st_appname = localappname;
 				strcpy(localactivity, (char *) beentry->st_activity);
-				localentry->st_activity = localactivity;
+				localentry->backendStatus.st_activity = localactivity;
 			}
 
 			if (save_changecount == beentry->st_changecount &&
@@ -2846,8 +2870,12 @@ pgstat_read_current_status(void)
 
 		beentry++;
 		/* Only valid entries get included into the local array */
-		if (localentry->st_procpid > 0)
+		if (localentry->backendStatus.st_procpid > 0)
 		{
+			BackendIdGetTransactionIds(i,
+									   &localentry->backend_xid,
+									   &localentry->backend_xmin);
+
 			localentry++;
 			localappname += NAMEDATALEN;
 			localactivity += pgstat_track_activity_query_size;
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index e7c3fb2..e6805d9 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -25,6 +25,7 @@
 #include "storage/shmem.h"
 #include "storage/sinvaladt.h"
 #include "storage/spin.h"
+#include "access/transam.h"
 
 
 /*
@@ -401,6 +402,37 @@ BackendIdGetProc(int backendID)
 }
 
 /*
+ * BackendIdGetTransactionIds
+ *		Get the xid and xmin of the backend. The result may be out of date
+ *		arbitrarily quickly, so the caller must be careful about how this
+ *		information is used.
+ */
+void
+BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmin)
+{
+	ProcState  *stateP;
+	SISeg	   *segP = shmInvalBuffer;
+	PGXACT	   *xact;
+
+	*xid = InvalidTransactionId;
+	*xmin = InvalidTransactionId;
+
+	/* Need to lock out additions/removals of backends */
+	LWLockAcquire(SInvalWriteLock, LW_SHARED);
+
+	if (backendID > 0 && backendID <= segP->lastBackend)
+	{
+		stateP = &segP->procState[backendID - 1];
+		xact = &ProcGlobal->allPgXact[stateP->proc->pgprocno];
+
+		*xid = xact->xid;
+		*xmin = xact->xmin;
+	}
+
+	LWLockRelease(SInvalWriteLock);
+}
+
+/*
  * SIInsertDataEntries
  *		Add new invalidation message(s) to the buffer.
  */
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index a4f31cf..e65b079 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -536,7 +536,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 
 		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
-		tupdesc = CreateTemplateTupleDesc(14, false);
+		tupdesc = CreateTemplateTupleDesc(16, false);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid",
 						   OIDOID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "pid",
@@ -565,6 +565,10 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 						   TEXTOID, -1, 0);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 14, "client_port",
 						   INT4OID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 15, "backend_xid",
+						   XIDOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 16, "backend_xmin",
+						   XIDOID, -1, 0);
 
 		funcctx->tuple_desc = BlessTupleDesc(tupdesc);
 
@@ -588,11 +592,11 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 
 			for (i = 1; i <= n; i++)
 			{
-				PgBackendStatus *be = pgstat_fetch_stat_beentry(i);
+				LocalPgBackendStatus *be = pgstat_fetch_stat_local_beentry(i);
 
 				if (be)
 				{
-					if (be->st_procpid == pid)
+					if (be->backendStatus.st_procpid == pid)
 					{
 						*(int *) (funcctx->user_fctx) = i;
 						break;
@@ -616,10 +620,10 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 	if (funcctx->call_cntr < funcctx->max_calls)
 	{
 		/* for each row */
-		Datum		values[14];
-		bool		nulls[14];
+		Datum		values[16];
+		bool		nulls[16];
 		HeapTuple	tuple;
-		PgBackendStatus *beentry;
+		LocalPgBackendStatus *beentry;
 
 		MemSet(values, 0, sizeof(values));
 		MemSet(nulls, 0, sizeof(nulls));
@@ -627,12 +631,12 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 		if (*(int *) (funcctx->user_fctx) > 0)
 		{
 			/* Get specific pid slot */
-			beentry = pgstat_fetch_stat_beentry(*(int *) (funcctx->user_fctx));
+			beentry = pgstat_fetch_stat_local_beentry(*(int *) (funcctx->user_fctx));
 		}
 		else
 		{
 			/* Get the next one in the list */
-			beentry = pgstat_fetch_stat_beentry(funcctx->call_cntr + 1);		/* 1-based index */
+			beentry = pgstat_fetch_stat_local_beentry(funcctx->call_cntr + 1);		/* 1-based index */
 		}
 		if (!beentry)
 		{
@@ -649,20 +653,26 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 		}
 
 		/* Values available to all callers */
-		values[0] = ObjectIdGetDatum(beentry->st_databaseid);
-		values[1] = Int32GetDatum(beentry->st_procpid);
-		values[2] = ObjectIdGetDatum(beentry->st_userid);
-		if (beentry->st_appname)
-			values[3] = CStringGetTextDatum(beentry->st_appname);
+		values[0] = ObjectIdGetDatum(beentry->backendStatus.st_databaseid);
+		values[1] = Int32GetDatum(beentry->backendStatus.st_procpid);
+		values[2] = ObjectIdGetDatum(beentry->backendStatus.st_userid);
+		if (beentry->backendStatus.st_appname)
+			values[3] = CStringGetTextDatum(beentry->backendStatus.st_appname);
 		else
 			nulls[3] = true;
 
+		values[14] = TransactionIdGetDatum(beentry->backend_xid);
+		nulls[14] = false;
+
+		values[15] = TransactionIdGetDatum(beentry->backend_xmin);
+		nulls[15] = false;
+
 		/* Values only available to same user or superuser */
-		if (superuser() || beentry->st_userid == GetUserId())
+		if (superuser() || beentry->backendStatus.st_userid == GetUserId())
 		{
 			SockAddr	zero_clientaddr;
 
-			switch (beentry->st_state)
+			switch (beentry->backendStatus.st_state)
 			{
 				case STATE_IDLE:
 					values[4] = CStringGetTextDatum("idle");
@@ -687,32 +697,32 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					break;
 			}
 
-			values[5] = CStringGetTextDatum(beentry->st_activity);
-			values[6] = BoolGetDatum(beentry->st_waiting);
+			values[5] = CStringGetTextDatum(beentry->backendStatus.st_activity);
+			values[6] = BoolGetDatum(beentry->backendStatus.st_waiting);
 
-			if (beentry->st_xact_start_timestamp != 0)
-				values[7] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
+			if (beentry->backendStatus.st_xact_start_timestamp != 0)
+				values[7] = TimestampTzGetDatum(beentry->backendStatus.st_xact_start_timestamp);
 			else
 				nulls[7] = true;
 
-			if (beentry->st_activity_start_timestamp != 0)
-				values[8] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
+			if (beentry->backendStatus.st_activity_start_timestamp != 0)
+				values[8] = TimestampTzGetDatum(beentry->backendStatus.st_activity_start_timestamp);
 			else
 				nulls[8] = true;
 
-			if (beentry->st_proc_start_timestamp != 0)
-				values[9] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
+			if (beentry->backendStatus.st_proc_start_timestamp != 0)
+				values[9] = TimestampTzGetDatum(beentry->backendStatus.st_proc_start_timestamp);
 			else
 				nulls[9] = true;
 
-			if (beentry->st_state_start_timestamp != 0)
-				values[10] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
+			if (beentry->backendStatus.st_state_start_timestamp != 0)
+				values[10] = TimestampTzGetDatum(beentry->backendStatus.st_state_start_timestamp);
 			else
 				nulls[10] = true;
 
 			/* A zeroed client addr means we don't know */
 			memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
-			if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
+			if (memcmp(&(beentry->backendStatus.st_clientaddr), &zero_clientaddr,
 					   sizeof(zero_clientaddr)) == 0)
 			{
 				nulls[11] = true;
@@ -721,9 +731,9 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			}
 			else
 			{
-				if (beentry->st_clientaddr.addr.ss_family == AF_INET
+				if (beentry->backendStatus.st_clientaddr.addr.ss_family == AF_INET
 #ifdef HAVE_IPV6
-					|| beentry->st_clientaddr.addr.ss_family == AF_INET6
+					|| beentry->backendStatus.st_clientaddr.addr.ss_family == AF_INET6
 #endif
 					)
 				{
@@ -733,18 +743,18 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 
 					remote_host[0] = '\0';
 					remote_port[0] = '\0';
-					ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
-											 beentry->st_clientaddr.salen,
+					ret = pg_getnameinfo_all(&beentry->backendStatus.st_clientaddr.addr,
+											 beentry->backendStatus.st_clientaddr.salen,
 											 remote_host, sizeof(remote_host),
 											 remote_port, sizeof(remote_port),
 											 NI_NUMERICHOST | NI_NUMERICSERV);
 					if (ret == 0)
 					{
-						clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
+						clean_ipv6_addr(beentry->backendStatus.st_clientaddr.addr.ss_family, remote_host);
 						values[11] = DirectFunctionCall1(inet_in,
 											   CStringGetDatum(remote_host));
-						if (beentry->st_clienthostname)
-							values[12] = CStringGetTextDatum(beentry->st_clienthostname);
+						if (beentry->backendStatus.st_clienthostname)
+							values[12] = CStringGetTextDatum(beentry->backendStatus.st_clienthostname);
 						else
 							nulls[12] = true;
 						values[13] = Int32GetDatum(atoi(remote_port));
@@ -756,7 +766,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 						nulls[13] = true;
 					}
 				}
-				else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
+				else if (beentry->backendStatus.st_clientaddr.addr.ss_family == AF_UNIX)
 				{
 					/*
 					 * Unix sockets always reports NULL for host and -1 for
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 11c1e1a..c001412 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2632,7 +2632,7 @@ DATA(insert OID = 3057 ( pg_stat_get_autoanalyze_count PGNSP PGUID 12 1 0 0 0 f
 DESCR("statistics: number of auto analyzes for a table");
 DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 0 f f f f t t s 0 0 23 "" _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
 DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23,28,28}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 3099 (  pg_stat_get_wal_senders	PGNSP PGUID 12 1 10 0 0 f f f f f t s 0 0 2249 "" "{23,25,25,25,25,25,23,25}" "{o,o,o,o,o,o,o,o}" "{pid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active replication");
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 5b2e460..e41d991 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -735,6 +735,31 @@ typedef struct PgBackendStatus
 	char	   *st_activity;
 } PgBackendStatus;
 
+/* ----------
+ * LocalPgBackendStatus
+ *
+ * When we build the backend status array, we use LocalPgBackendStatus to be
+ * able to add new values to the struct when needed without adding new fields
+ * to the shared memory. It contains the backend status as a first member.
+ * ----------
+ */
+typedef struct LocalPgBackendStatus
+{
+	/* Local version of the backend status entry
+	 */
+	PgBackendStatus backendStatus;
+
+	/* The xid of the current transaction if available, InvalidTransactionId
+	 * if not
+	 */
+	TransactionId backend_xid;
+
+	/* The xmin of the current session if available, InvalidTransactionId
+	 * if not
+	 */
+	TransactionId backend_xmin;
+} LocalPgBackendStatus;
+
 /*
  * Working state needed to accumulate per-function-call timing statistics.
  */
@@ -907,6 +932,7 @@ extern void pgstat_send_bgwriter(void);
 extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);
 extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
 extern PgBackendStatus *pgstat_fetch_stat_beentry(int beid);
+extern LocalPgBackendStatus *pgstat_fetch_stat_local_beentry(int beid);
 extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
 extern int	pgstat_fetch_stat_numbackends(void);
 extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void);
diff --git a/src/include/storage/sinvaladt.h b/src/include/storage/sinvaladt.h
index 5f2ce48..9b45b3e 100644
--- a/src/include/storage/sinvaladt.h
+++ b/src/include/storage/sinvaladt.h
@@ -32,6 +32,7 @@ extern Size SInvalShmemSize(void);
 extern void CreateSharedInvalidationState(void);
 extern void SharedInvalBackendInit(bool sendOnly);
 extern PGPROC *BackendIdGetProc(int backendID);
+extern void BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmin);
 
 extern void SIInsertDataEntries(const SharedInvalidationMessage *data, int n);
 extern int	SIGetDataEntries(SharedInvalidationMessage *data, int datasize);
