diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index de450cd661..12263f5fd5 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -103,6 +103,7 @@
 <!ENTITY archive-modules SYSTEM "archive-modules.sgml">
 <!ENTITY protocol   SYSTEM "protocol.sgml">
 <!ENTITY sources    SYSTEM "sources.sgml">
+<!ENTITY transactions    SYSTEM "xact.sgml">
 <!ENTITY storage    SYSTEM "storage.sgml">
 <!ENTITY tablesample-method SYSTEM "tablesample-method.sgml">
 <!ENTITY generic-wal SYSTEM "generic-wal.sgml">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index ee515cec8f..6aca1e756a 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -24635,6 +24635,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         Returns the current transaction's ID.  It will assign a new one if the
         current transaction does not have one already (because it has not
         performed any database updates).
+        If executed in a subtransaction this will return the top-level xid.
        </para></entry>
       </row>
 
@@ -24651,6 +24652,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         ID is assigned yet.  (It's best to use this variant if the transaction
         might otherwise be read-only, to avoid unnecessary consumption of an
         XID.)
+        If executed in a subtransaction this will return the top-level xid.
        </para></entry>
       </row>
 
@@ -24694,6 +24696,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
        <para>
         Returns a current <firstterm>snapshot</firstterm>, a data structure
         showing which transaction IDs are now in-progress.
+        Only top-level xids are included in the snapshot; subxids are not shown.
        </para></entry>
       </row>
 
@@ -24748,7 +24751,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         Is the given transaction ID <firstterm>visible</firstterm> according
         to this snapshot (that is, was it completed before the snapshot was
         taken)?  Note that this function will not give the correct answer for
-        a subtransaction ID.
+        a subtransaction ID (subxid).
        </para></entry>
       </row>
      </tbody>
@@ -24807,7 +24810,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
         xmax</literal> and not in this list was already completed at the time
         of the snapshot, and thus is either visible or dead according to its
         commit status.  This list does not include the transaction IDs of
-        subtransactions.
+        subtransactions (subxids).
        </entry>
       </row>
      </tbody>
diff --git a/doc/src/sgml/ref/commit.sgml b/doc/src/sgml/ref/commit.sgml
index 5f244cdd3c..53d830998c 100644
--- a/doc/src/sgml/ref/commit.sgml
+++ b/doc/src/sgml/ref/commit.sgml
@@ -62,6 +62,9 @@ COMMIT [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ]
       linkend="sql-set-transaction"/>) as the just finished one.  Otherwise,
       no new transaction is started.
      </para>
+     <para>
+      The SQL Standard describes this as a chained transaction.
+     </para>
     </listitem>
    </varlistentry>
   </variablelist>
diff --git a/doc/src/sgml/ref/rollback.sgml b/doc/src/sgml/ref/rollback.sgml
index 142f71e774..02b118fc04 100644
--- a/doc/src/sgml/ref/rollback.sgml
+++ b/doc/src/sgml/ref/rollback.sgml
@@ -56,11 +56,14 @@ ROLLBACK [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ]
     <term><literal>AND CHAIN</literal></term>
     <listitem>
      <para>
-      If <literal>AND CHAIN</literal> is specified, a new transaction is
+      If <literal>AND CHAIN</literal> is specified, a new unaborted transaction is
       immediately started with the same transaction characteristics (see <xref
       linkend="sql-set-transaction"/>) as the just finished one.  Otherwise,
       no new transaction is started.
      </para>
+     <para>
+      The SQL Standard describes this as a chained transaction.
+     </para>
     </listitem>
    </varlistentry>
   </variablelist>
diff --git a/doc/src/sgml/xact.sgml b/doc/src/sgml/xact.sgml
new file mode 100644
index 0000000000..bff4d8ae18
--- /dev/null
+++ b/doc/src/sgml/xact.sgml
@@ -0,0 +1,201 @@
+<!-- doc/src/sgml/xact.sgml -->
+
+<chapter id="transactions">
+
+<title>Transaction Management</title>
+
+<para>
+This chapter provides an overview of transaction management for
+<productname>PostgreSQL</productname> databases.
+The word transaction is often abbreviated to "xact".
+</para>
+
+<para>
+PostgreSQL supports transactions and chained transactions according to the
+SQL Standard. PostgreSQL supports SAVEPOINTs through the implementation
+defined mechanism of subtransactions, which offer a superset of the required
+features. Prepared transactions allow PostgreSQL to implement what SQL
+Standard refers to as encompassing transactions belonging to an external
+agent.
+</para>
+
+<para>
+Some features implemented in other databases, such as
+autonomous transactions and nested transactions are not supported
+by PostgreSQL, though be careful since those terms may be used slightly
+differently in various external contexts.
+</para>
+
+<sect1 id="transaction-id">
+
+<title>Transactions and Identifiers</title>
+
+<para>
+Transactions may be started explicitly using BEGIN and COMMIT commands, known as
+a transaction block. A transaction will also be started and ended implicitly for
+each request when outside of a transaction block.
+</para>
+
+<para>
+All transactions are identified by a unique VirtualTransactionId (virtualxid or
+vxid), e.g. 4/12532, which is comprised of the BackendId (in this example, 4)
+and a sequentially assigned number unique to that backend, known as LocalXid
+(in this example, 12532).
+</para>
+
+<para>
+If a transaction attempts to write to the database it will be assigned a
+TransactionId (xid), e.g. 278394. xids are assigned sequentially using a global
+counter used by all databases within a postgresql cluster (instance). This
+property is used by the transaction system to say that if one xid is earlier
+than another xid then the earlier transaction attempted to write before the
+later xid. However, the start and end of those two transactions are not
+constrained to occur in that sequence.
+</para>
+
+<para>
+When a top-level transaction with an assigned xid commits, it is marked as
+committed in the pg_xact directory. Additional information may also be recorded
+in the pg_commit_ts directory.
+</para>
+
+<para>
+The internal transaction ID type xid is 32 bits wide and wraps around every
+4 billion transactions. There is also a 64-bit type xid8 that does not wrap
+around during the life of an installation, and can be converted to xid by
+casting if required.
+</para>
+
+<para>
+Functions to inspect xids are shown in in Table 9.81, which return values of
+type xid8.
+</para>
+
+<para>
+xids are used as the basis for PostgreSQL's MVCC visibility mechanism,
+described elsewhere.
+Hot Standby, or Read Replica servers, emulate the transaction management
+details described here so that users have MVCC visibility with read-only
+transactions.
+</para>
+
+</sect1>
+
+<sect1 id="xact-locking">
+
+<title>Transactions and Locking</title>
+
+<para>
+Currently executing transactions are shown in the pg_locks view in columns
+"virtualxid" (text) and "transactionid" (xid), if an xid has been assigned.
+Read transactions will have a virtualxid but a NULL xid, while write
+transactions will have both a virtualxid and an xid assigned.
+</para>
+
+<para>
+Virtualxid is a text column, rather than a separate datatype.
+</para>
+
+<para>
+Lock waits on table-level locks are shown against virtualxid, while lock waits
+against row-level locks are shown against transactionid.
+</para>
+
+<para>
+Row-level locks are recorded directly onto the locked rows. Row-level locks can
+be inspected using the pgrowlocks extension.
+</para>
+
+<para>
+Row-level read locks may require the assignment of a multixact ID (mxid), which
+are recorded in the pg_multixact directory.
+</para>
+
+</sect1>
+
+<sect1 id="subxacts">
+
+<title>Subtransactions</title>
+
+<para>
+Subtransactions may be started from the main transaction, also known as the
+top-level transaction. Subtransactions can also be started from other
+subtransactions. As a result, the arrangement of transaction and subtransactions
+form a hierarchy or tree. Thus, each subtransaction has one parent transaction.
+Over time, a transaction may have many child subtransactions.
+The word subtransaction is often abbreviated to "subxact".
+</para>
+
+<para>
+At present in PostgreSQL, only one transaction or subtransaction can be active at
+one time. When a subtransaction ends, the parent transaction becomes active again.
+</para>
+
+<para>
+Subtransactions may end via a commit or abort without affecting their parent
+transaction, allowing the parent transaction to continue.
+</para>
+
+<para>
+Subtransactions may be started explicitly by using the SAVEPOINT command, but may
+also be started in other ways, such as PL/pgSQL's EXCEPTION clause. PL/Python and
+PL/TCL also support explicit subtransactions. Working with C API, users may also
+call BeginInternalSubTransaction().
+</para>
+
+<para>
+If a subtransaction is assigned an xid, we refer to this as a subxid. Read-only
+subtransactions are not assigned a subxid, but when a subtransaction attempts to
+write it will be assigned a subxid. We ensure that all of a subxid's parents, up
+to and including the top-level transaction are also assigned an xid. We ensure
+that a parent xid is always earlier than any of its child subxids.
+</para>
+
+<para>
+The parent xid of each subxid is recorded in the pg_subtrans directory. No entry is
+made for top-level xids since they do not have a parent, nor is an entry made for
+read only subtransactions.
+</para>
+
+<para>
+When a subtransaction commits, all of the committed child subtransactions with
+assigned subxids will be recorded as committed. When a top-level transaction with
+an assigned xid commits, all of its committed child subtransactions are also
+marked as committed in the pg_xact directory.
+</para>
+
+<para>
+The more subtransactions each transaction uses, the greater the overhead for
+transaction management. Up to 64 subxids are cached in shmem for each backend,
+after that point, the overhead increases more significantly since we must look up
+the entry in pg_subtrans for each xid.
+</para>
+
+</sect1>
+
+<sect1 id="xact-prepared">
+
+<title>Prepared Transactions</title>
+
+<para>
+PostgreSQL also supports Prepared Transactions using the PREPARE TRANSACTION and
+then COMMIT PREPARED/ROLLBACK PREPARED commands.
+Those commands are extensions to the SQL Standard, since the SQL syntax is not yet
+yet part of the standard, though the Standard does refer to encompassing
+transactions made by an external SQL agent. Prepared transactions are intended
+for use programmatically by extenal transaction management systems.
+PostgreSQL follows the features and model proposed by the
+X/Open XA standard, but does not implement some less often used aspects.
+The XA protocol is a multi-phase protocol that allows multiple distributed
+systems to work together in a transactional manner, which is why this is also
+known as two-phase commit (2PC).
+</para>
+
+<para>
+Information relating to these is stored in pg_twophase. Currently prepared
+transactions can be inspected using pg_prepared_xacts view.
+</para>
+
+</sect1>
+
+</chapter>
