← Back to team overview

maria-developers team mailing list archive

[andrei.elkin@xxxxxxxxxxx] 25fe744e5c3: MDEV-742 XA PREPAREd transaction survive disconnect/server restart

 

Howdy, Kristian.

I am forwarding for your attention a patch that HEADs bb-10.5-mdev_742
branch. While it's of some size maybe you'll find some time to review
changes/extension esp done to the pararellel slave.

Looking forward to hear from you!

Thanks.

Andrei

revision-id: 25fe744e5c3d2e8f7d3db7eed37d8e412837457b (mariadb-10.5.0-283-g25fe744e5c3)
parent(s): 36cebe53a3645bf1e665ffdf5b552cabcc1e8e56
author: Andrei Elkin
committer: Andrei Elkin
timestamp: 2020-03-04 15:48:43 +0200
message:

MDEV-742 XA PREPAREd transaction survive disconnect/server restart

Lifted long standing limitation to the XA of rolling it back at the
transaction's
connection close even if the XA is prepared.

Prepared XA-transaction is made to sustain connection close or server
restart.
The patch consists of

    - binary logging extension to write prepared XA part of
      transaction signified with
      its XID in a new XA_prepare_log_event. The concusion part -
      with Commit or Rollback decision - is logged separately as
      Query_log_event.
      That is in the binlog the XA consists of two separate group of
      events.

      That makes the whole XA possibly interweaving in binlog with
      other XA:s or regular transaction but with no harm to
      replication and data consistency.

      Gtid_log_event receives two more flags to identify which of the
      two XA phases of the transaction it represents. With either flag
      set also XID info is added to the event.

    - engines are made aware of the server policy to keep up user
      prepared XA:s so they (Innodb, rocksdb) don't roll them back
      anymore at their disconnect methods.

    - slave applier is refined to cope with two phase logged XA:s
      including parallel modes of execution.

This patch does not address crash-safe logging of the new events which
is being addressed by MDEV-21469, its commit is to be published shortly.

There's a list of fixes to 10.5 that were required by this MDEV, incl

  MDEV-21856: XID::formatID is constrained to 4 bytes by requirements of 
      cross-platform replication and Innodb legacy.
  MDEV-21659 XA rollback 'foreign_xid' is allowed inside active XA
  MDEV-21766 Forbid XID with empty 'gtrid'
  MDEV-21854 xa commit 'xid' one phase for already prepared transaction must always error out


Many thanks to Alexey Botchkov for driving this work initially!

---
 mysql-test/include/kill_and_restart_mysqld.inc     |   15 +
 mysql-test/main/flush_read_lock.result             |   76 +-
 mysql-test/main/flush_read_lock.test               |  112 +-
 mysql-test/main/xa.result                          |   61 +
 mysql-test/main/xa.test                            |   49 +
 mysql-test/main/xa_binlog.result                   |   11 +-
 mysql-test/main/xa_binlog.test                     |    2 +-
 mysql-test/main/xa_prepared_binlog_off-master.opt  |    1 +
 mysql-test/main/xa_prepared_binlog_off.result      | 1044 +++++++++++++++++
 mysql-test/main/xa_prepared_binlog_off.test        |   11 +
 mysql-test/main/xa_sync.result                     |   10 +
 mysql-test/main/xa_sync.test                       |    5 +
 .../include/binlog_xa_prepare_connection.inc       |   31 +
 .../include/binlog_xa_prepare_disconnect.inc       |   35 +
 .../include/binlog_xa_prepared_do_and_restart.inc  |  323 ++++++
 .../suite/binlog/r/binlog_xa_checkpoint.result     |   33 +
 .../suite/binlog/r/binlog_xa_prepared.result       | 1176 ++++++++++++++++++++
 .../binlog/r/binlog_xa_prepared_disconnect.result  | 1176 ++++++++++++++++++++
 .../suite/binlog/t/binlog_xa_checkpoint.test       |   57 +
 mysql-test/suite/binlog/t/binlog_xa_prepared.inc   |  102 ++
 .../binlog/t/binlog_xa_prepared_disconnect.test    |   11 +
 .../suite/rpl/include/rpl_xa_mixed_engines.inc     |  183 +++
 .../suite/rpl/r/rpl_parallel_optimistic_xa.result  |   51 +
 .../r/rpl_parallel_optimistic_xa_lsu_off.result    |   51 +
 .../suite/rpl/r/rpl_parallel_xa_same_xid.result    |   23 +
 mysql-test/suite/rpl/r/rpl_temporary_errors.result |   47 +-
 mysql-test/suite/rpl/r/rpl_xa.result               |   48 +
 mysql-test/suite/rpl/r/rpl_xa_gap_lock.result      |   44 +
 .../suite/rpl/r/rpl_xa_gtid_pos_auto_engine.result |   64 ++
 .../suite/rpl/r/rpl_xa_survive_disconnect.result   |  319 ++++++
 .../rpl/r/rpl_xa_survive_disconnect_lsu_off.result |  319 ++++++
 .../rpl_xa_survive_disconnect_mixed_engines.result |  373 +++++++
 .../suite/rpl/t/rpl_parallel_optimistic_xa.test    |  235 ++++
 .../t/rpl_parallel_optimistic_xa_lsu_off-slave.opt |    1 +
 .../rpl/t/rpl_parallel_optimistic_xa_lsu_off.test  |    2 +
 .../suite/rpl/t/rpl_parallel_xa_same_xid.test      |  138 +++
 mysql-test/suite/rpl/t/rpl_temporary_errors.test   |   82 +-
 mysql-test/suite/rpl/t/rpl_xa.inc                  |   73 ++
 mysql-test/suite/rpl/t/rpl_xa.test                 |    5 +
 mysql-test/suite/rpl/t/rpl_xa_gap_lock-slave.opt   |    1 +
 mysql-test/suite/rpl/t/rpl_xa_gap_lock.test        |  137 +++
 .../suite/rpl/t/rpl_xa_gtid_pos_auto_engine.test   |   29 +
 .../suite/rpl/t/rpl_xa_survive_disconnect.test     |  294 +++++
 .../t/rpl_xa_survive_disconnect_lsu_off-slave.opt  |    2 +
 .../rpl/t/rpl_xa_survive_disconnect_lsu_off.test   |    8 +
 .../t/rpl_xa_survive_disconnect_mixed_engines.test |   68 ++
 sql/handler.cc                                     |   11 +-
 sql/log.cc                                         |  248 ++++-
 sql/log.h                                          |   10 +
 sql/log_event.cc                                   |   59 +-
 sql/log_event.h                                    |  213 +++-
 sql/log_event_client.cc                            |   37 +-
 sql/log_event_server.cc                            |  298 +++--
 sql/rpl_parallel.cc                                |  220 +++-
 sql/rpl_parallel.h                                 |   28 +-
 sql/rpl_rli.cc                                     |   14 +-
 sql/rpl_rli.h                                      |    4 +
 sql/slave.cc                                       |   10 +-
 sql/sql_repl.cc                                    |    4 +-
 sql/xa.cc                                          |  254 ++++-
 sql/xa.h                                           |   22 +-
 storage/innobase/handler/ha_innodb.cc              |    1 +
 storage/innobase/trx/trx0trx.cc                    |   19 +-
 storage/rocksdb/ha_rocksdb.cc                      |   18 +-
 storage/rocksdb/mysql-test/rocksdb/r/xa.result     |   41 +-
 storage/rocksdb/mysql-test/rocksdb/t/xa.test       |   43 +-
 .../rocksdb/mysql-test/rocksdb_rpl/r/rpl_xa.result |   50 +
 .../rocksdb/mysql-test/rocksdb_rpl/t/rpl_xa.inc    |   70 ++
 .../rocksdb/mysql-test/rocksdb_rpl/t/rpl_xa.test   |    6 +
 .../tokudb/mysql-test/tokudb_mariadb/r/xa.result   |    1 +
 storage/tokudb/mysql-test/tokudb_mariadb/t/xa.test |    3 +
 71 files changed, 8410 insertions(+), 212 deletions(-)

diff --git a/mysql-test/include/kill_and_restart_mysqld.inc b/mysql-test/include/kill_and_restart_mysqld.inc
new file mode 100644
index 00000000000..b67fb7350b4
--- /dev/null
+++ b/mysql-test/include/kill_and_restart_mysqld.inc
@@ -0,0 +1,15 @@
+if (!$restart_parameters)
+{
+  let $restart_parameters = restart;
+}
+
+--let $_server_id= `SELECT @@server_id`
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect
+
+--echo # Kill and $restart_parameters
+--exec echo "$restart_parameters" > $_expect_file_name
+--shutdown_server 0
+--source include/wait_until_disconnected.inc
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+--disable_reconnect
diff --git a/mysql-test/main/flush_read_lock.result b/mysql-test/main/flush_read_lock.result
index 0f8c2ce9fb9..be710050139 100644
--- a/mysql-test/main/flush_read_lock.result
+++ b/mysql-test/main/flush_read_lock.result
@@ -1310,6 +1310,8 @@ unlock tables;
 # Check that XA non-COMMIT statements are not and COMMIT is
 # blocked by active FTWRL in another connection
 #
+# XA COMMIT, XA ROLLBACK and XA PREPARE does take COMMIT lock to ensure
+# that nothing is written to bin log and redo log under FTWRL mode.
 connection con1;
 flush tables with read lock;
 connection default;
@@ -1322,11 +1324,25 @@ connection con1;
 flush tables with read lock;
 connection default;
 xa end 'test1';
-xa prepare 'test1';
+xa prepare 'test1';;
+connection con1;
+unlock tables;
+# Switching to connection 'default'.
+connection default;
+# Reap XA PREPARE.
+# Switching to connection 'con1'.
+connection con1;
+flush tables with read lock;
+# Switching to connection 'default'.
+connection default;
+# Send XA ROLLBACK 'test1'
 xa rollback 'test1';
+# Switching to connection 'con1'.
 connection con1;
+# Wait until XA ROLLBACK is blocked.
 unlock tables;
 connection default;
+# Reap XA ROLLBACK
 xa start 'test1';
 insert into t3_trans values (1);
 connection con1;
@@ -1334,7 +1350,20 @@ flush tables with read lock;
 connection default;
 connection default;
 xa end 'test1';
+# Send XA PREPARE 'test1'
 xa prepare 'test1';
+# Switching to connection 'con1'.
+connection con1;
+# Wait until XA PREPARE is blocked.
+unlock tables;
+# Switching to connection 'default'.
+connection default;
+# Reap XA PREPARE.
+# Switching to connection 'con1'.
+connection con1;
+flush tables with read lock;
+# Switching to connection 'default'.
+connection default;
 # Send:
 xa commit 'test1';;
 connection con1;
@@ -1344,6 +1373,51 @@ connection default;
 # Reap XA COMMIT.
 delete from t3_trans;
 #
+# Check that XA COMMIT / ROLLBACK for prepared transaction from a
+# disconnected session is blocked by active FTWRL in another connection.
+#
+# Create temporary connection for XA transaction.
+connect  con_tmp,localhost,root,,;
+xa start 'test1';
+insert into t3_trans values (1);
+xa end 'test1';
+xa prepare 'test1';
+# Disconnect temporary connection
+disconnect con_tmp;
+# Create temporary connection for XA transaction.
+connect  con_tmp,localhost,root,,;
+xa start 'test2';
+insert into t3_trans values (2);
+xa end 'test2';
+xa prepare 'test2';
+# Disconnect temporary connection
+disconnect con_tmp;
+# Switching to connection 'con1'.
+connection con1;
+flush tables with read lock;
+# Switching to connection 'default'.
+connection default;
+# Send XA ROLLBACK 'test1'
+xa rollback 'test1';
+# Switching to connection 'con1'.
+connection con1;
+# Wait until XA ROLLBACK is blocked.
+unlock tables;
+flush tables with read lock;
+# Switching to connection 'default'.
+connection default;
+# Reap XA ROLLBACK
+# Send XA COMMIT
+xa commit 'test2';;
+# Switching to connection 'con1'.
+connection con1;
+# Wait until XA COMMIT is blocked.
+unlock tables;
+# Switching to connection 'default'.
+connection default;
+# Reap XA COMMIT.
+delete from t3_trans;
+#
 # Check that XA COMMIT blocks FTWRL in another connection.
 xa start 'test1';
 insert into t3_trans values (1);
diff --git a/mysql-test/main/flush_read_lock.test b/mysql-test/main/flush_read_lock.test
index 80512deac4e..4283358770c 100644
--- a/mysql-test/main/flush_read_lock.test
+++ b/mysql-test/main/flush_read_lock.test
@@ -1592,6 +1592,8 @@ unlock tables;
 --echo # Check that XA non-COMMIT statements are not and COMMIT is
 --echo # blocked by active FTWRL in another connection
 --echo #
+--echo # XA COMMIT, XA ROLLBACK and XA PREPARE does take COMMIT lock to ensure
+--echo # that nothing is written to bin log and redo log under FTWRL mode.
 connection $con_aux1;
 flush tables with read lock;
 connection default;
@@ -1604,11 +1606,37 @@ connection $con_aux1;
 flush tables with read lock;
 connection default;
 xa end 'test1';
-xa prepare 'test1';
-xa rollback 'test1';
+--send xa prepare 'test1';
 connection $con_aux1;
+let $wait_condition=
+  select count(*) = 1 from information_schema.processlist
+  where state = "Waiting for backup lock" and
+        info = "xa prepare 'test1'";
+--source include/wait_condition.inc
 unlock tables;
+--echo # Switching to connection 'default'.
+connection default;
+--echo # Reap XA PREPARE.
+--reap
+--echo # Switching to connection '$con_aux1'.
+connection $con_aux1;
+flush tables with read lock;
+--echo # Switching to connection 'default'.
 connection default;
+--echo # Send XA ROLLBACK 'test1'
+--send xa rollback 'test1'
+--echo # Switching to connection '$con_aux1'.
+connection $con_aux1;
+--echo # Wait until XA ROLLBACK is blocked.
+let $wait_condition=
+  select count(*) = 1 from information_schema.processlist
+  where state = "Waiting for backup lock" and
+        info = "xa rollback 'test1'";
+--source include/wait_condition.inc
+unlock tables;
+connection default;
+--echo # Reap XA ROLLBACK
+--reap
 xa start 'test1';
 insert into t3_trans values (1);
 connection $con_aux1;
@@ -1616,7 +1644,27 @@ flush tables with read lock;
 connection default;
 connection default;
 xa end 'test1';
-xa prepare 'test1';
+--echo # Send XA PREPARE 'test1'
+--send xa prepare 'test1'
+--echo # Switching to connection '$con_aux1'.
+connection $con_aux1;
+--echo # Wait until XA PREPARE is blocked.
+let $wait_condition=
+  select count(*) = 1 from information_schema.processlist
+  where state = "Waiting for backup lock" and
+        info = "xa prepare 'test1'";
+--source include/wait_condition.inc
+unlock tables;
+--echo # Switching to connection 'default'.
+connection default;
+--echo # Reap XA PREPARE.
+--reap
+--echo # Switching to connection '$con_aux1'.
+connection $con_aux1;
+flush tables with read lock;
+--echo # Switching to connection 'default'.
+connection default;
+
 --echo # Send:
 --send xa commit 'test1';
 connection $con_aux1;
@@ -1631,6 +1679,64 @@ connection default;
 --echo # Reap XA COMMIT.
 --reap
 delete from t3_trans;
+--echo #
+--echo # Check that XA COMMIT / ROLLBACK for prepared transaction from a
+--echo # disconnected session is blocked by active FTWRL in another connection.
+--echo #
+--echo # Create temporary connection for XA transaction.
+connect (con_tmp,localhost,root,,);
+xa start 'test1';
+insert into t3_trans values (1);
+xa end 'test1';
+xa prepare 'test1';
+--echo # Disconnect temporary connection
+disconnect con_tmp;
+--echo # Create temporary connection for XA transaction.
+connect (con_tmp,localhost,root,,);
+xa start 'test2';
+insert into t3_trans values (2);
+xa end 'test2';
+xa prepare 'test2';
+--echo # Disconnect temporary connection
+disconnect con_tmp;
+--echo # Switching to connection '$con_aux1'.
+connection $con_aux1;
+flush tables with read lock;
+--echo # Switching to connection 'default'.
+connection default;
+--echo # Send XA ROLLBACK 'test1'
+--send xa rollback 'test1'
+--echo # Switching to connection '$con_aux1'.
+connection $con_aux1;
+--echo # Wait until XA ROLLBACK is blocked.
+let $wait_condition=
+  select count(*) = 1 from information_schema.processlist
+  where state = "Waiting for backup lock" and
+        info = "xa rollback 'test1'";
+--source include/wait_condition.inc
+unlock tables;
+flush tables with read lock;
+--echo # Switching to connection 'default'.
+connection default;
+--echo # Reap XA ROLLBACK
+--reap
+--echo # Send XA COMMIT
+--send xa commit 'test2';
+--echo # Switching to connection '$con_aux1'.
+connection $con_aux1;
+--echo # Wait until XA COMMIT is blocked.
+let $wait_condition=
+  select count(*) = 1 from information_schema.processlist
+  where state = "Waiting for backup lock" and
+        info = "xa commit 'test2'";
+--source include/wait_condition.inc
+unlock tables;
+--echo # Switching to connection 'default'.
+connection default;
+--echo # Reap XA COMMIT.
+--reap
+delete from t3_trans;
+
 --echo #
 --echo # Check that XA COMMIT blocks FTWRL in another connection.
 xa start 'test1';
diff --git a/mysql-test/main/xa.result b/mysql-test/main/xa.result
index bd2946247d8..aa48f6d26c7 100644
--- a/mysql-test/main/xa.result
+++ b/mysql-test/main/xa.result
@@ -66,6 +66,9 @@ select * from t1;
 a
 20
 disconnect con1;
+xa rollback 'testb',0x2030405060,11;
+xa recover;
+formatID	gtrid_length	bqual_length	data
 connection default;
 xa start 'tr1';
 insert t1 values (40);
@@ -376,3 +379,61 @@ XA PREPARE 'Я_упaлa_c_сеновала_тормозила_головой';
 XA ROLLBACK 'Я_упaлa_c_сеновала_тормозила_головой';
 SET NAMES default;
 DROP TABLE t1;
+# MDEV-7974 related
+# Check XA state when lock_wait_timeout happens
+# More tests added to flush_read_lock.test
+connect  con_tmp,localhost,root,,;
+set session lock_wait_timeout=1;
+create table asd (a int) engine=innodb;
+xa start 'test1';
+insert into asd values(1);
+xa end 'test1';
+connection default;
+flush table with read lock;
+connection con_tmp;
+# PREPARE error will do auto rollback.
+xa prepare 'test1';
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+show errors;
+Level	Code	Message
+Error	1205	Lock wait timeout exceeded; try restarting transaction
+Error	1402	XA_RBROLLBACK: Transaction branch was rolled back
+connection default;
+unlock tables;
+connection con_tmp;
+xa start 'test1';
+insert into asd values(1);
+xa end 'test1';
+xa prepare 'test1';
+connection default;
+flush tables with read lock;
+connection con_tmp;
+# LOCK error during ROLLBACK will not alter transaction state.
+xa rollback 'test1';
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+show errors;
+Level	Code	Message
+Error	1205	Lock wait timeout exceeded; try restarting transaction
+Error	1401	XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency
+xa recover;
+formatID	gtrid_length	bqual_length	data
+1	5	0	test1
+# LOCK error during COMMIT will not alter transaction state.
+xa commit 'test1';
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+show errors;
+Level	Code	Message
+Error	1205	Lock wait timeout exceeded; try restarting transaction
+Error	1401	XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency
+xa recover;
+formatID	gtrid_length	bqual_length	data
+1	5	0	test1
+connection default;
+unlock tables;
+connection con_tmp;
+xa rollback 'test1';
+xa recover;
+formatID	gtrid_length	bqual_length	data
+drop table asd;
+disconnect con_tmp;
+connection default;
diff --git a/mysql-test/main/xa.test b/mysql-test/main/xa.test
index 55c41452635..ca09989dfc8 100644
--- a/mysql-test/main/xa.test
+++ b/mysql-test/main/xa.test
@@ -98,6 +98,8 @@ xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
 select * from t1;
 disconnect con1;
 --source include/wait_until_count_sessions.inc
+xa rollback 'testb',0x2030405060,11;
+xa recover;
 
 connection default;
 
@@ -523,3 +525,50 @@ SET NAMES default;
 DROP TABLE t1;
 
 --source include/wait_until_count_sessions.inc
+
+--echo # MDEV-7974 related
+--echo # Check XA state when lock_wait_timeout happens
+--echo # More tests added to flush_read_lock.test
+connect (con_tmp,localhost,root,,);
+set session lock_wait_timeout=1;
+create table asd (a int) engine=innodb;
+xa start 'test1';
+insert into asd values(1);
+xa end 'test1';
+connection default;
+flush table with read lock;
+connection con_tmp;
+--echo # PREPARE error will do auto rollback.
+--ERROR ER_LOCK_WAIT_TIMEOUT
+xa prepare 'test1';
+show errors;
+connection default;
+unlock tables;
+
+connection con_tmp;
+xa start 'test1';
+insert into asd values(1);
+xa end 'test1';
+xa prepare 'test1';
+connection default;
+flush tables with read lock;
+connection con_tmp;
+--echo # LOCK error during ROLLBACK will not alter transaction state.
+--ERROR ER_LOCK_WAIT_TIMEOUT
+xa rollback 'test1';
+show errors;
+xa recover;
+--echo # LOCK error during COMMIT will not alter transaction state.
+--ERROR ER_LOCK_WAIT_TIMEOUT
+xa commit 'test1';
+show errors;
+xa recover;
+connection default;
+unlock tables;
+connection con_tmp;
+xa rollback 'test1';
+xa recover;
+drop table asd;
+disconnect con_tmp;
+--source include/wait_until_disconnected.inc
+connection default;
diff --git a/mysql-test/main/xa_binlog.result b/mysql-test/main/xa_binlog.result
index 619a6e08b20..c45749d500f 100644
--- a/mysql-test/main/xa_binlog.result
+++ b/mysql-test/main/xa_binlog.result
@@ -18,14 +18,17 @@ a
 1
 2
 3
-SHOW BINLOG EVENTS LIMIT 3,9;
+SHOW BINLOG EVENTS LIMIT 3,12;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
-master-bin.000001	#	Gtid	1	#	BEGIN GTID #-#-#
+master-bin.000001	#	Gtid	1	#	XA START X'786174657374',X'',1 GTID #-#-#
 master-bin.000001	#	Query	1	#	use `test`; INSERT INTO t1 VALUES (1)
-master-bin.000001	#	Query	1	#	COMMIT
+master-bin.000001	#	Query	1	#	XA END X'786174657374',X'',1
+master-bin.000001	#	XA_prepare	1	#	XA PREPARE X'786174657374',X'',1
+master-bin.000001	#	Gtid	1	#	GTID #-#-#
+master-bin.000001	#	Query	1	#	XA COMMIT X'786174657374',X'',1
 master-bin.000001	#	Gtid	1	#	BEGIN GTID #-#-#
 master-bin.000001	#	Query	1	#	use `test`; INSERT INTO t1 VALUES (2)
-master-bin.000001	#	Query	1	#	COMMIT
+master-bin.000001	#	Xid	1	#	COMMIT /* xid=XX */
 master-bin.000001	#	Gtid	1	#	BEGIN GTID #-#-#
 master-bin.000001	#	Query	1	#	use `test`; INSERT INTO t1 VALUES (3)
 master-bin.000001	#	Xid	1	#	COMMIT /* xid=XX */
diff --git a/mysql-test/main/xa_binlog.test b/mysql-test/main/xa_binlog.test
index ecbf1f4f066..91bca2ac8cb 100644
--- a/mysql-test/main/xa_binlog.test
+++ b/mysql-test/main/xa_binlog.test
@@ -27,6 +27,6 @@ SELECT * FROM t1 ORDER BY a;
 
 --replace_column 2 # 5 #
 --replace_regex /xid=[0-9]+/xid=XX/ /GTID [0-9]+-[0-9]+-[0-9]+/GTID #-#-#/
-SHOW BINLOG EVENTS LIMIT 3,9;
+SHOW BINLOG EVENTS LIMIT 3,12;
 
 DROP TABLE t1;
diff --git a/mysql-test/main/xa_prepared_binlog_off-master.opt b/mysql-test/main/xa_prepared_binlog_off-master.opt
new file mode 100644
index 00000000000..789275fa25e
--- /dev/null
+++ b/mysql-test/main/xa_prepared_binlog_off-master.opt
@@ -0,0 +1 @@
+--skip-log-bin
diff --git a/mysql-test/main/xa_prepared_binlog_off.result b/mysql-test/main/xa_prepared_binlog_off.result
new file mode 100644
index 00000000000..ca19f6cdfaf
--- /dev/null
+++ b/mysql-test/main/xa_prepared_binlog_off.result
@@ -0,0 +1,1044 @@
+call mtr.add_suppression("You need to use --log-bin to make --log-slave-updates work.");
+connection default;
+CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
+call mtr.add_suppression("Found 10 prepared XA transactions");
+CREATE TABLE t (a INT) ENGINE=innodb;
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx1tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx1tmp';
+XA PREPARE 'trx1tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx2tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx2tmp';
+XA PREPARE 'trx2tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx3tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx3tmp';
+XA PREPARE 'trx3tmp';
+connection default;
+XA COMMIT 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA ROLLBACK 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA START 'trx1tmp';
+ERROR XAE08: XAER_DUPID: The XID already exists
+connection default;
+*** 3 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1tmp;
+disconnect conn1tmp;
+connection default;
+XA COMMIT 'trx1tmp';
+KILL connection CONN_ID;
+XA COMMIT 'trx3tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1ro';
+SELECT * from t ORDER BY a;
+a
+XA END     'trx1ro';
+XA PREPARE 'trx1ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2ro';
+SELECT * from t ORDER BY a;
+a
+XA END     'trx2ro';
+XA PREPARE 'trx2ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3ro';
+SELECT * from t ORDER BY a;
+a
+XA END     'trx3ro';
+XA PREPARE 'trx3ro';
+connection default;
+*** 4 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1ro;
+disconnect conn1ro;
+connection default;
+XA ROLLBACK 'trx1ro';
+KILL connection CONN_ID;
+XA ROLLBACK 'trx3ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1empty';
+XA END     'trx1empty';
+XA PREPARE 'trx1empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2empty';
+XA END     'trx2empty';
+XA PREPARE 'trx2empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3empty';
+XA END     'trx3empty';
+XA PREPARE 'trx3empty';
+connection default;
+*** 5 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1empty;
+disconnect conn1empty;
+connection default;
+XA COMMIT 'trx1empty';
+KILL connection CONN_ID;
+XA COMMIT 'trx3empty';
+connect conn1$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1unprepared';
+INSERT INTO t set a=0;
+XA END     'trx1unprepared';
+INSERT INTO t set a=0;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+disconnect conn1unprepared;
+connection default;
+XA COMMIT 'trx1unprepared';
+ERROR XAE04: XAER_NOTA: Unknown XID
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_0';
+INSERT INTO t SET a=0;
+XA END     'trx_0';
+XA PREPARE 'trx_0';
+disconnect conn0;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_1';
+INSERT INTO t SET a=1;
+XA END     'trx_1';
+XA PREPARE 'trx_1';
+disconnect conn1;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_2';
+INSERT INTO t SET a=2;
+XA END     'trx_2';
+XA PREPARE 'trx_2';
+disconnect conn2;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_3';
+INSERT INTO t SET a=3;
+XA END     'trx_3';
+XA PREPARE 'trx_3';
+disconnect conn3;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_4';
+INSERT INTO t SET a=4;
+XA END     'trx_4';
+XA PREPARE 'trx_4';
+disconnect conn4;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_5';
+INSERT INTO t SET a=5;
+XA END     'trx_5';
+XA PREPARE 'trx_5';
+disconnect conn5;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_6';
+INSERT INTO t SET a=6;
+XA END     'trx_6';
+XA PREPARE 'trx_6';
+disconnect conn6;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_7';
+INSERT INTO t SET a=7;
+XA END     'trx_7';
+XA PREPARE 'trx_7';
+disconnect conn7;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_8';
+INSERT INTO t SET a=8;
+XA END     'trx_8';
+XA PREPARE 'trx_8';
+disconnect conn8;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_9';
+INSERT INTO t SET a=9;
+XA END     'trx_9';
+XA PREPARE 'trx_9';
+disconnect conn9;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_10';
+INSERT INTO t SET a=10;
+XA END     'trx_10';
+XA PREPARE 'trx_10';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_11';
+INSERT INTO t SET a=11;
+XA END     'trx_11';
+XA PREPARE 'trx_11';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_12';
+INSERT INTO t SET a=12;
+XA END     'trx_12';
+XA PREPARE 'trx_12';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_13';
+INSERT INTO t SET a=13;
+XA END     'trx_13';
+XA PREPARE 'trx_13';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_14';
+INSERT INTO t SET a=14;
+XA END     'trx_14';
+XA PREPARE 'trx_14';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_15';
+INSERT INTO t SET a=15;
+XA END     'trx_15';
+XA PREPARE 'trx_15';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_16';
+INSERT INTO t SET a=16;
+XA END     'trx_16';
+XA PREPARE 'trx_16';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_17';
+INSERT INTO t SET a=17;
+XA END     'trx_17';
+XA PREPARE 'trx_17';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_18';
+INSERT INTO t SET a=18;
+XA END     'trx_18';
+XA PREPARE 'trx_18';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_19';
+INSERT INTO t SET a=19;
+XA END     'trx_19';
+XA PREPARE 'trx_19';
+connection default;
+KILL CONNECTION CONN_ID;
+connection default;
+XA ROLLBACK 'trx_0';
+XA ROLLBACK 'trx_1';
+XA ROLLBACK 'trx_2';
+XA ROLLBACK 'trx_3';
+XA ROLLBACK 'trx_4';
+XA COMMIT 'trx_5';
+XA COMMIT 'trx_6';
+XA COMMIT 'trx_7';
+XA COMMIT 'trx_8';
+XA COMMIT 'trx_9';
+# restart
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_0';
+INSERT INTO t SET a=0;
+XA END     'new_trx_0';
+XA PREPARE 'new_trx_0';
+disconnect conn_restart_0;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_1';
+INSERT INTO t SET a=1;
+XA END     'new_trx_1';
+XA PREPARE 'new_trx_1';
+disconnect conn_restart_1;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_2';
+INSERT INTO t SET a=2;
+XA END     'new_trx_2';
+XA PREPARE 'new_trx_2';
+disconnect conn_restart_2;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_3';
+INSERT INTO t SET a=3;
+XA END     'new_trx_3';
+XA PREPARE 'new_trx_3';
+disconnect conn_restart_3;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_4';
+INSERT INTO t SET a=4;
+XA END     'new_trx_4';
+XA PREPARE 'new_trx_4';
+disconnect conn_restart_4;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_5';
+INSERT INTO t SET a=5;
+XA END     'new_trx_5';
+XA PREPARE 'new_trx_5';
+disconnect conn_restart_5;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_6';
+INSERT INTO t SET a=6;
+XA END     'new_trx_6';
+XA PREPARE 'new_trx_6';
+disconnect conn_restart_6;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_7';
+INSERT INTO t SET a=7;
+XA END     'new_trx_7';
+XA PREPARE 'new_trx_7';
+disconnect conn_restart_7;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_8';
+INSERT INTO t SET a=8;
+XA END     'new_trx_8';
+XA PREPARE 'new_trx_8';
+disconnect conn_restart_8;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_9';
+INSERT INTO t SET a=9;
+XA END     'new_trx_9';
+XA PREPARE 'new_trx_9';
+disconnect conn_restart_9;
+connection default;
+connection default;
+XA COMMIT  'new_trx_0';
+XA COMMIT  'new_trx_1';
+XA COMMIT  'new_trx_2';
+XA COMMIT  'new_trx_3';
+XA COMMIT  'new_trx_4';
+XA COMMIT  'new_trx_5';
+XA COMMIT  'new_trx_6';
+XA COMMIT  'new_trx_7';
+XA COMMIT  'new_trx_8';
+XA COMMIT  'new_trx_9';
+XA START 'trx_10';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_10';
+XA START 'trx_11';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_11';
+XA START 'trx_12';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_12';
+XA START 'trx_13';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_13';
+XA START 'trx_14';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_14';
+XA START 'trx_15';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_15';
+XA START 'trx_16';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_16';
+XA START 'trx_17';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_17';
+XA START 'trx_18';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_18';
+XA START 'trx_19';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_19';
+SELECT * FROM t;
+a
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+disconnect conn2tmp;
+disconnect conn3tmp;
+disconnect conn2ro;
+disconnect conn3ro;
+disconnect conn2empty;
+disconnect conn3empty;
+connection default;
+XA ROLLBACK 'trx_20';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn19;
+connection default;
+XA ROLLBACK 'trx_19';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn18;
+connection default;
+XA ROLLBACK 'trx_18';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn17;
+connection default;
+XA ROLLBACK 'trx_17';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn16;
+connection default;
+XA ROLLBACK 'trx_16';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn15;
+connection default;
+XA ROLLBACK 'trx_15';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn14;
+connection default;
+XA ROLLBACK 'trx_14';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn13;
+connection default;
+XA ROLLBACK 'trx_13';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn12;
+connection default;
+XA ROLLBACK 'trx_12';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn11;
+connection default;
+XA ROLLBACK 'trx_11';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn10;
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx1tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx1tmp';
+XA PREPARE 'trx1tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx2tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx2tmp';
+XA PREPARE 'trx2tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx3tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx3tmp';
+XA PREPARE 'trx3tmp';
+connection default;
+XA COMMIT 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA ROLLBACK 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA START 'trx1tmp';
+ERROR XAE08: XAER_DUPID: The XID already exists
+connection default;
+*** 3 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1tmp;
+disconnect conn1tmp;
+connection default;
+XA COMMIT 'trx1tmp';
+KILL connection CONN_ID;
+XA COMMIT 'trx3tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1ro';
+SELECT * from t ORDER BY a;
+a
+0
+1
+2
+3
+4
+5
+5
+6
+6
+7
+7
+8
+8
+9
+9
+10
+11
+12
+13
+14
+XA END     'trx1ro';
+XA PREPARE 'trx1ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2ro';
+SELECT * from t ORDER BY a;
+a
+0
+1
+2
+3
+4
+5
+5
+6
+6
+7
+7
+8
+8
+9
+9
+10
+11
+12
+13
+14
+XA END     'trx2ro';
+XA PREPARE 'trx2ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3ro';
+SELECT * from t ORDER BY a;
+a
+0
+1
+2
+3
+4
+5
+5
+6
+6
+7
+7
+8
+8
+9
+9
+10
+11
+12
+13
+14
+XA END     'trx3ro';
+XA PREPARE 'trx3ro';
+connection default;
+*** 4 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1ro;
+disconnect conn1ro;
+connection default;
+XA ROLLBACK 'trx1ro';
+KILL connection CONN_ID;
+XA ROLLBACK 'trx3ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1empty';
+XA END     'trx1empty';
+XA PREPARE 'trx1empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2empty';
+XA END     'trx2empty';
+XA PREPARE 'trx2empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3empty';
+XA END     'trx3empty';
+XA PREPARE 'trx3empty';
+connection default;
+*** 5 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1empty;
+disconnect conn1empty;
+connection default;
+XA COMMIT 'trx1empty';
+KILL connection CONN_ID;
+XA COMMIT 'trx3empty';
+connect conn1$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1unprepared';
+INSERT INTO t set a=0;
+XA END     'trx1unprepared';
+INSERT INTO t set a=0;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+disconnect conn1unprepared;
+connection default;
+XA COMMIT 'trx1unprepared';
+ERROR XAE04: XAER_NOTA: Unknown XID
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_0';
+INSERT INTO t SET a=0;
+XA END     'trx_0';
+XA PREPARE 'trx_0';
+disconnect conn0;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_1';
+INSERT INTO t SET a=1;
+XA END     'trx_1';
+XA PREPARE 'trx_1';
+disconnect conn1;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_2';
+INSERT INTO t SET a=2;
+XA END     'trx_2';
+XA PREPARE 'trx_2';
+disconnect conn2;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_3';
+INSERT INTO t SET a=3;
+XA END     'trx_3';
+XA PREPARE 'trx_3';
+disconnect conn3;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_4';
+INSERT INTO t SET a=4;
+XA END     'trx_4';
+XA PREPARE 'trx_4';
+disconnect conn4;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_5';
+INSERT INTO t SET a=5;
+XA END     'trx_5';
+XA PREPARE 'trx_5';
+disconnect conn5;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_6';
+INSERT INTO t SET a=6;
+XA END     'trx_6';
+XA PREPARE 'trx_6';
+disconnect conn6;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_7';
+INSERT INTO t SET a=7;
+XA END     'trx_7';
+XA PREPARE 'trx_7';
+disconnect conn7;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_8';
+INSERT INTO t SET a=8;
+XA END     'trx_8';
+XA PREPARE 'trx_8';
+disconnect conn8;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_9';
+INSERT INTO t SET a=9;
+XA END     'trx_9';
+XA PREPARE 'trx_9';
+disconnect conn9;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_10';
+INSERT INTO t SET a=10;
+XA END     'trx_10';
+XA PREPARE 'trx_10';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_11';
+INSERT INTO t SET a=11;
+XA END     'trx_11';
+XA PREPARE 'trx_11';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_12';
+INSERT INTO t SET a=12;
+XA END     'trx_12';
+XA PREPARE 'trx_12';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_13';
+INSERT INTO t SET a=13;
+XA END     'trx_13';
+XA PREPARE 'trx_13';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_14';
+INSERT INTO t SET a=14;
+XA END     'trx_14';
+XA PREPARE 'trx_14';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_15';
+INSERT INTO t SET a=15;
+XA END     'trx_15';
+XA PREPARE 'trx_15';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_16';
+INSERT INTO t SET a=16;
+XA END     'trx_16';
+XA PREPARE 'trx_16';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_17';
+INSERT INTO t SET a=17;
+XA END     'trx_17';
+XA PREPARE 'trx_17';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_18';
+INSERT INTO t SET a=18;
+XA END     'trx_18';
+XA PREPARE 'trx_18';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_19';
+INSERT INTO t SET a=19;
+XA END     'trx_19';
+XA PREPARE 'trx_19';
+connection default;
+KILL CONNECTION CONN_ID;
+connection default;
+XA ROLLBACK 'trx_0';
+XA ROLLBACK 'trx_1';
+XA ROLLBACK 'trx_2';
+XA ROLLBACK 'trx_3';
+XA ROLLBACK 'trx_4';
+XA COMMIT 'trx_5';
+XA COMMIT 'trx_6';
+XA COMMIT 'trx_7';
+XA COMMIT 'trx_8';
+XA COMMIT 'trx_9';
+# Kill and restart
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_0';
+INSERT INTO t SET a=0;
+XA END     'new_trx_0';
+XA PREPARE 'new_trx_0';
+disconnect conn_restart_0;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_1';
+INSERT INTO t SET a=1;
+XA END     'new_trx_1';
+XA PREPARE 'new_trx_1';
+disconnect conn_restart_1;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_2';
+INSERT INTO t SET a=2;
+XA END     'new_trx_2';
+XA PREPARE 'new_trx_2';
+disconnect conn_restart_2;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_3';
+INSERT INTO t SET a=3;
+XA END     'new_trx_3';
+XA PREPARE 'new_trx_3';
+disconnect conn_restart_3;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_4';
+INSERT INTO t SET a=4;
+XA END     'new_trx_4';
+XA PREPARE 'new_trx_4';
+disconnect conn_restart_4;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_5';
+INSERT INTO t SET a=5;
+XA END     'new_trx_5';
+XA PREPARE 'new_trx_5';
+disconnect conn_restart_5;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_6';
+INSERT INTO t SET a=6;
+XA END     'new_trx_6';
+XA PREPARE 'new_trx_6';
+disconnect conn_restart_6;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_7';
+INSERT INTO t SET a=7;
+XA END     'new_trx_7';
+XA PREPARE 'new_trx_7';
+disconnect conn_restart_7;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_8';
+INSERT INTO t SET a=8;
+XA END     'new_trx_8';
+XA PREPARE 'new_trx_8';
+disconnect conn_restart_8;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_9';
+INSERT INTO t SET a=9;
+XA END     'new_trx_9';
+XA PREPARE 'new_trx_9';
+disconnect conn_restart_9;
+connection default;
+connection default;
+XA COMMIT  'new_trx_0';
+XA COMMIT  'new_trx_1';
+XA COMMIT  'new_trx_2';
+XA COMMIT  'new_trx_3';
+XA COMMIT  'new_trx_4';
+XA COMMIT  'new_trx_5';
+XA COMMIT  'new_trx_6';
+XA COMMIT  'new_trx_7';
+XA COMMIT  'new_trx_8';
+XA COMMIT  'new_trx_9';
+XA START 'trx_10';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_10';
+XA START 'trx_11';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_11';
+XA START 'trx_12';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_12';
+XA START 'trx_13';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_13';
+XA START 'trx_14';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_14';
+XA START 'trx_15';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_15';
+XA START 'trx_16';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_16';
+XA START 'trx_17';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_17';
+XA START 'trx_18';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_18';
+XA START 'trx_19';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_19';
+SELECT * FROM t;
+a
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+disconnect conn2tmp;
+disconnect conn3tmp;
+disconnect conn2ro;
+disconnect conn3ro;
+disconnect conn2empty;
+disconnect conn3empty;
+connection default;
+XA ROLLBACK 'trx_20';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn19;
+connection default;
+XA ROLLBACK 'trx_19';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn18;
+connection default;
+XA ROLLBACK 'trx_18';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn17;
+connection default;
+XA ROLLBACK 'trx_17';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn16;
+connection default;
+XA ROLLBACK 'trx_16';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn15;
+connection default;
+XA ROLLBACK 'trx_15';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn14;
+connection default;
+XA ROLLBACK 'trx_14';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn13;
+connection default;
+XA ROLLBACK 'trx_13';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn12;
+connection default;
+XA ROLLBACK 'trx_12';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn11;
+connection default;
+XA ROLLBACK 'trx_11';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn10;
+connection default;
+XA START   'one_phase_trx_0';
+INSERT INTO t SET a=0;
+XA END     'one_phase_trx_0';
+XA COMMIT  'one_phase_trx_0' ONE PHASE;
+XA START   'one_phase_trx_1';
+INSERT INTO t SET a=1;
+XA END     'one_phase_trx_1';
+XA COMMIT  'one_phase_trx_1' ONE PHASE;
+XA START   'one_phase_trx_2';
+INSERT INTO t SET a=2;
+XA END     'one_phase_trx_2';
+XA COMMIT  'one_phase_trx_2' ONE PHASE;
+XA START   'one_phase_trx_3';
+INSERT INTO t SET a=3;
+XA END     'one_phase_trx_3';
+XA COMMIT  'one_phase_trx_3' ONE PHASE;
+XA START   'one_phase_trx_4';
+INSERT INTO t SET a=4;
+XA END     'one_phase_trx_4';
+XA COMMIT  'one_phase_trx_4' ONE PHASE;
+SELECT SUM(a) FROM t;
+SUM(a)
+290
+DROP TABLE t;
+DROP VIEW v_processlist;
+All transactions must be completed, to empty-list the following:
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
diff --git a/mysql-test/main/xa_prepared_binlog_off.test b/mysql-test/main/xa_prepared_binlog_off.test
new file mode 100644
index 00000000000..edbfa7c2825
--- /dev/null
+++ b/mysql-test/main/xa_prepared_binlog_off.test
@@ -0,0 +1,11 @@
+###############################################################################
+# MDEV-7974 (bug#12161 Xa recovery and client disconnection)
+# Testing XA behaviour with binlog turned off.
+###############################################################################
+
+--source include/not_valgrind.inc
+--source include/not_embedded.inc
+
+# Common part with XA binlogging testing
+call mtr.add_suppression("You need to use --log-bin to make --log-slave-updates work.");
+--source suite/binlog/t/binlog_xa_prepared.inc
diff --git a/mysql-test/main/xa_sync.result b/mysql-test/main/xa_sync.result
index 1482ff5cacf..e7dd9b02847 100644
--- a/mysql-test/main/xa_sync.result
+++ b/mysql-test/main/xa_sync.result
@@ -18,6 +18,11 @@ disconnect con1;
 SET debug_sync='now SIGNAL go';
 connection con2;
 ERROR XAE04: XAER_NOTA: Unknown XID
+*** Must have 'xatest' in the list
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	6	0	xatest
+XA COMMIT 'xatest';
 disconnect con2;
 connection default;
 SET debug_sync='RESET';
@@ -37,6 +42,11 @@ disconnect con1;
 SET debug_sync='now SIGNAL go';
 connection con2;
 ERROR XAE04: XAER_NOTA: Unknown XID
+*** Must have 'xatest' in the list
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	6	0	xatest
+XA ROLLBACK 'xatest';
 disconnect con2;
 connection default;
 SET debug_sync='RESET';
diff --git a/mysql-test/main/xa_sync.test b/mysql-test/main/xa_sync.test
index bb95af7c0ba..2fe7337501e 100644
--- a/mysql-test/main/xa_sync.test
+++ b/mysql-test/main/xa_sync.test
@@ -35,6 +35,11 @@ while ($i)
   connection con2;
   --error ER_XAER_NOTA
   reap;
+  --echo *** Must have 'xatest' in the list
+  XA RECOVER;
+  # second time yields no error
+  --error 0
+  --eval $op
   disconnect con2;
 
   connection default;
diff --git a/mysql-test/suite/binlog/include/binlog_xa_prepare_connection.inc b/mysql-test/suite/binlog/include/binlog_xa_prepare_connection.inc
new file mode 100644
index 00000000000..c0041af1e7f
--- /dev/null
+++ b/mysql-test/suite/binlog/include/binlog_xa_prepare_connection.inc
@@ -0,0 +1,31 @@
+#
+# This file initiate connections to run XA transactions up to
+# their prepare.
+# Connection name, transaction name and its content depends on
+# supplied parameters.
+#
+# param $type        type of transaction
+# param $index       index identifies the connection with those of type $type
+# param $sql_init1   a query to execute once connection is established
+# param $sql_init2   a query to execute once connection is established
+# param $sql_doit    a query to execute inside transaction
+#                    Note, the query may depend on tables created by caller
+#
+
+--connect (conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,)
+if ($sql_init1)
+{
+  --eval $sql_init1
+}
+if ($sql_init2)
+{
+  --eval $sql_init2
+}
+
+--eval XA START   'trx$index$type'
+if ($sql_doit)
+{
+  --eval $sql_doit
+}
+--eval XA END     'trx$index$type'
+--eval XA PREPARE 'trx$index$type'
diff --git a/mysql-test/suite/binlog/include/binlog_xa_prepare_disconnect.inc b/mysql-test/suite/binlog/include/binlog_xa_prepare_disconnect.inc
new file mode 100644
index 00000000000..1f6ce713cc9
--- /dev/null
+++ b/mysql-test/suite/binlog/include/binlog_xa_prepare_disconnect.inc
@@ -0,0 +1,35 @@
+#
+# This file disconnects two connections. One actively and one through
+# kill. It is included by binlog_xa_prepared_do_and_restart.
+#
+# param $type              type of transaction
+# param $terminate_with    how to conclude actively disconnecte:
+#                          XA COMMIT or XA ROLLBACK
+# param $conn3_id          connection id of the being killed.
+# param $num_trx_prepared  number of transactions prepared so far
+#
+--connection default
+
+--echo *** $num_trx_prepared prepared transactions must be in the list ***
+--replace_column 2 LEN1 3 LEN2 4 TRX_N
+XA RECOVER;
+
+--connection conn1$type
+--let $conn1_id=`SELECT connection_id()`
+--disconnect conn1$type
+
+--connection default
+--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn1_id
+--source include/wait_condition.inc
+
+# It will conclude now
+--eval  $terminate_with 'trx1$type'
+
+--replace_result $conn3_id CONN_ID
+--eval KILL connection $conn3_id
+
+--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn3_id
+--source include/wait_condition.inc
+
+# It will conclude now
+--eval  $terminate_with 'trx3$type'
diff --git a/mysql-test/suite/binlog/include/binlog_xa_prepared_do_and_restart.inc b/mysql-test/suite/binlog/include/binlog_xa_prepared_do_and_restart.inc
new file mode 100644
index 00000000000..cbd740fdae4
--- /dev/null
+++ b/mysql-test/suite/binlog/include/binlog_xa_prepared_do_and_restart.inc
@@ -0,0 +1,323 @@
+#
+# This file creates various kinds of prepared XA transactions,
+# manipulates their connection state and examines how their prepared
+# status behave while the transaction is disconnected, killed or
+# the server kisses it shutdown.
+# The file can be sourced multiple times
+# param $restart_number (as the number of inclusion) adjusts
+# verification logics.
+#
+# param [in] $conn_number      Total number of connection each performing
+#                              one insert into table.
+# param [in] $commit_number    Number of commits from either.
+#                              side of the server restart.
+# param [in] $rollback_number  The same as the above just for rollback.
+# param [in] $term_number      Number of transaction that are terminated
+#                              before server restarts
+# param [in] $killed_number    Instead of disconnect make some
+#                              connections killed when their
+#                              transactions got prepared.
+# param [in] $server_disconn_number  Make some connections disconnected
+#                              by shutdown rather than actively
+# param [in] $post_restart_conn_number  Number a "warmup" connection
+#                              after server restart, they all commit
+# param [out] restart_number   Counter to be incremented at the end of the test
+#
+
+# The test consists of three sections:
+# I.   Corner cases check
+# II.  Regular case check
+# III. Post server-restart verification
+
+
+#
+# I. Corner cases of
+#
+# A. XA with an update to a temp table
+# B. XA with SELECT
+# C. XA empty
+# Demonstrate their XA status upon prepare and how they react on disconnect and
+# shutdown.
+# In each of A,B,C three prepared transactions are set up.
+# trx1 is for disconnection, trx2 for shutdown, trx3 for being killed.
+# The A case additionally contains some XA prohibited state transaction check.
+#
+# D. Prove that not prepared XA remains to be cleared out by disconnection.
+#
+
+#
+# A. The temp table only prepared XA recovers only formally to
+#    let post recovery XA COMMIT or XA ROLLBACK with no effect.
+
+--let $type = tmp
+--let $index = 1
+--let $sql_init1 = SET @@sql_log_bin = OFF
+--let $sql_init2 = CREATE TEMPORARY TABLE tmp$index (a int) ENGINE=innodb
+--let $sql_doit  = INSERT INTO tmp$index SET a=$index
+--source suite/binlog/include/binlog_xa_prepare_connection.inc
+
+--let $index = 2
+--source suite/binlog/include/binlog_xa_prepare_connection.inc
+
+--let $index = 3
+--source suite/binlog/include/binlog_xa_prepare_connection.inc
+--let $conn3_id=`SELECT connection_id()`
+
+#
+# Various prohibited XA state changes to test here:
+#
+
+--connection default
+# Stealing is not allowed
+--error ER_XAER_NOTA
+--eval  XA COMMIT 'trx1$type'
+--error ER_XAER_NOTA
+--eval  XA ROLLBACK 'trx1$type'
+
+# Before disconnect: creating a duplicate is not allowed
+--error ER_XAER_DUPID
+--eval  XA START 'trx1$type'
+
+# Manipulate now the prepared transactions.
+# Two to terminate, one to leave out.
+--let $terminate_with = XA COMMIT
+--let $num_trx_prepared = $index
+--source suite/binlog/include/binlog_xa_prepare_disconnect.inc
+
+#
+# B. "Read-only" (select) prepared XA recovers only formally to
+#    let post recovery XA COMMIT or XA ROLLBACK with no effect.
+#
+--let $type=ro
+--let $index = 1
+--let $sql_init1 =
+--let $sql_init2 =
+--let $sql_doit  = SELECT * from t ORDER BY a
+--source suite/binlog/include/binlog_xa_prepare_connection.inc
+
+--let $index = 2
+--source suite/binlog/include/binlog_xa_prepare_connection.inc
+
+--let $index = 3
+--source suite/binlog/include/binlog_xa_prepare_connection.inc
+--let $conn3_id=`SELECT connection_id()`
+
+--let $terminate_with = XA ROLLBACK
+# two three above section prepared transaction were terminated.
+--inc $num_trx_prepared
+--source suite/binlog/include/binlog_xa_prepare_disconnect.inc
+
+#
+# C. Empty prepared XA recovers only formally to
+#    let post recovery XA COMMIT or XA ROLLBACK with no effect.
+#
+--let $type=empty
+--let $index = 1
+--let $sql_init1 =
+--let $sql_init2 =
+--let $sql_doit  =
+--source suite/binlog/include/binlog_xa_prepare_connection.inc
+
+--let $index = 2
+--source suite/binlog/include/binlog_xa_prepare_connection.inc
+
+--let $index = 3
+--source suite/binlog/include/binlog_xa_prepare_connection.inc
+--let $conn3_id=`SELECT connection_id()`
+
+--let $terminate_with = XA COMMIT
+--inc $num_trx_prepared
+--source suite/binlog/include/binlog_xa_prepare_disconnect.inc
+
+#
+# D. Not prepared XA disconnects to be cleared out,
+#    no effect on data left as well.
+#    Few more prohibited XA state transactions is checked out.
+#
+--let $type=unprepared
+--let $prev_count=`SELECT count(*) from t`
+
+--connect(conn1$type, 127.0.0.1,root,,test,$MASTER_MYPORT,)
+--eval XA START   'trx1$type'
+INSERT INTO t set a=0;
+--eval XA END     'trx1$type'
+
+--error ER_XAER_RMFAIL
+INSERT INTO t set a=0;
+--error ER_XAER_RMFAIL
+--eval XA START 'trx1$type'
+--error ER_XAER_RMFAIL
+--eval XA START 'trx1$type'
+
+--disconnect conn1$type
+
+--connection default
+# No such transactions
+--error ER_XAER_NOTA
+--eval  XA COMMIT 'trx1$type'
+if (`SELECT count(*) > $prev_count from t`)
+{
+    --echo *** Unexpected commit to the table. ***
+    --die
+}
+
+#
+# II. Regular case.
+#
+# Prepared transactions get disconnected in three ways:
+# actively, being killed and by the server shutdown.
+#
+--let $i=0
+while ($i < $conn_number)
+{
+    --connect (conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,)
+    --let $conn_id=`SELECT connection_id()`
+      --disable_reconnect
+      SET @@binlog_format = STATEMENT;
+      if (`SELECT $i % 2`)
+      {
+         SET @@binlog_format = ROW;
+      }
+    --eval XA START   'trx_$i'
+    --eval INSERT INTO t SET a=$i
+    --eval XA END     'trx_$i'
+    --eval XA PREPARE 'trx_$i'
+
+    --let $disc_via_kill=`SELECT $conn_number - $i <= $killed_number`
+    if (!$disc_via_kill)
+    {
+      --let $disc_via_shutdown=`SELECT $conn_number - $i <= $killed_number + $server_disconn_number`
+      if (!$disc_via_shutdown)
+      {
+        --disconnect conn$i
+      }
+    }
+    if ($disc_via_kill)
+    {
+      --connection default
+      --replace_result $conn_id CONN_ID
+      --eval KILL CONNECTION $conn_id
+    }
+
+    if (!$disc_via_shutdown)
+    {
+      --connection default
+      --let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id
+      --source include/wait_condition.inc
+    }
+    --inc $i
+}
+
+# [0, $rollback_number - 1] are rolled back now
+--connection default
+
+--let $i=0
+while ($i < $rollback_number)
+{
+    --eval XA ROLLBACK 'trx_$i'
+
+    --inc $i
+}
+
+# [$rollback_number, $rollback_number + $commit_number - 1] get committed
+while ($i < $term_number)
+{
+    --eval XA COMMIT 'trx_$i'
+
+    --inc $i
+}
+
+--source include/$how_to_restart
+
+#
+# III. Post server-restart verification.
+# It concludes survived XA:s with a number of commits and rollbacks
+# as configured in the 1st part to check expected results in the end.
+# Cleanup section consists of explicit disconnect (for killed, or
+# not disconnected before shutdown).
+#
+
+# New XA can be prepared and committed
+--let $k = 0
+while ($k < $post_restart_conn_number)
+{
+    --connect (conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,)
+    --let  $conn_id=`SELECT connection_id()`
+    --eval XA START   'new_trx_$k'
+    --eval INSERT INTO t SET a=$k
+    --eval XA END     'new_trx_$k'
+    --eval XA PREPARE 'new_trx_$k'
+
+    --disconnect conn_restart_$k
+
+    --connection default
+    --let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id
+    --source include/wait_condition.inc
+
+    --inc $k
+}
+
+--connection default
+--let $k = 0
+while ($k < $post_restart_conn_number)
+{
+    --eval XA COMMIT  'new_trx_$k'
+    --inc $k
+}
+
+#
+# Symmetrically to the pre-restart, the resurrected trx:s are committed
+# [$term_number, $term_number + $commit_number - 1]
+# and the rest is rolled back.
+#
+--let $i = $term_number
+
+while ($i < `SELECT $term_number + $commit_number`)
+{
+    # Expected to fail
+    --error ER_XAER_DUPID
+    --eval XA START 'trx_$i'
+    --eval XA COMMIT 'trx_$i'
+    --inc $i
+}
+
+while ($i < $conn_number)
+{
+    # Expected to fail
+    --error ER_XAER_DUPID
+    --eval XA START 'trx_$i'
+    --eval XA ROLLBACK 'trx_$i'
+    --inc $i
+}
+
+#
+# Verification of correct results of recovered XA transaction handling:
+#
+SELECT * FROM t;
+
+--let $type=tmp
+--disconnect conn2$type
+--disconnect conn3$type
+--let $type=ro
+--disconnect conn2$type
+--disconnect conn3$type
+--let $type=empty
+--disconnect conn2$type
+--disconnect conn3$type
+
+--let $i= $conn_number
+--let $k= 0
+--let $expl_disconn_number = `SELECT $killed_number + $server_disconn_number`
+while ($k < $expl_disconn_number)
+{
+  --connection default
+    --error ER_XAER_NOTA
+    --eval  XA ROLLBACK 'trx_$i'
+
+  --dec $i
+  --disconnect conn$i
+
+  --inc $k
+}
+
+--inc $restart_number
diff --git a/mysql-test/suite/binlog/r/binlog_xa_checkpoint.result b/mysql-test/suite/binlog/r/binlog_xa_checkpoint.result
new file mode 100644
index 00000000000..d8a5818674f
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_xa_checkpoint.result
@@ -0,0 +1,33 @@
+RESET MASTER;
+CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb;
+connect con1,localhost,root,,;
+SET DEBUG_SYNC= "at_unlog_xa_prepare SIGNAL con1_ready WAIT_FOR con1_go";
+XA START '1';
+INSERT INTO t1 SET a=1;
+XA END '1';
+XA PREPARE '1';;
+connection default;
+SET DEBUG_SYNC= "now WAIT_FOR con1_ready";
+FLUSH LOGS;
+FLUSH LOGS;
+FLUSH LOGS;
+show binary logs;
+Log_name	File_size
+master-bin.000001	#
+master-bin.000002	#
+master-bin.000003	#
+master-bin.000004	#
+include/show_binlog_events.inc
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000004	#	Format_desc	#	#	SERVER_VERSION, BINLOG_VERSION
+master-bin.000004	#	Gtid_list	#	#	[#-#-#]
+master-bin.000004	#	Binlog_checkpoint	#	#	master-bin.000001
+SET DEBUG_SYNC= "now SIGNAL con1_go";
+connection con1;
+*** master-bin.000004 checkpoint must show up now ***
+connection con1;
+XA ROLLBACK '1';
+SET debug_sync = 'reset';
+connection default;
+DROP TABLE t1;
+SET debug_sync = 'reset';
diff --git a/mysql-test/suite/binlog/r/binlog_xa_prepared.result b/mysql-test/suite/binlog/r/binlog_xa_prepared.result
new file mode 100644
index 00000000000..9fda8ab3143
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_xa_prepared.result
@@ -0,0 +1,1176 @@
+connection default;
+RESET MASTER;
+CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
+call mtr.add_suppression("Found 10 prepared XA transactions");
+CREATE TABLE t (a INT) ENGINE=innodb;
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx1tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx1tmp';
+XA PREPARE 'trx1tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx2tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx2tmp';
+XA PREPARE 'trx2tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx3tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx3tmp';
+XA PREPARE 'trx3tmp';
+connection default;
+XA COMMIT 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA ROLLBACK 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA START 'trx1tmp';
+ERROR XAE08: XAER_DUPID: The XID already exists
+connection default;
+*** 3 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1tmp;
+disconnect conn1tmp;
+connection default;
+XA COMMIT 'trx1tmp';
+KILL connection CONN_ID;
+XA COMMIT 'trx3tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1ro';
+SELECT * from t ORDER BY a;
+a
+XA END     'trx1ro';
+XA PREPARE 'trx1ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2ro';
+SELECT * from t ORDER BY a;
+a
+XA END     'trx2ro';
+XA PREPARE 'trx2ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3ro';
+SELECT * from t ORDER BY a;
+a
+XA END     'trx3ro';
+XA PREPARE 'trx3ro';
+connection default;
+*** 4 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1ro;
+disconnect conn1ro;
+connection default;
+XA ROLLBACK 'trx1ro';
+KILL connection CONN_ID;
+XA ROLLBACK 'trx3ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1empty';
+XA END     'trx1empty';
+XA PREPARE 'trx1empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2empty';
+XA END     'trx2empty';
+XA PREPARE 'trx2empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3empty';
+XA END     'trx3empty';
+XA PREPARE 'trx3empty';
+connection default;
+*** 5 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1empty;
+disconnect conn1empty;
+connection default;
+XA COMMIT 'trx1empty';
+KILL connection CONN_ID;
+XA COMMIT 'trx3empty';
+connect conn1$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1unprepared';
+INSERT INTO t set a=0;
+XA END     'trx1unprepared';
+INSERT INTO t set a=0;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+disconnect conn1unprepared;
+connection default;
+XA COMMIT 'trx1unprepared';
+ERROR XAE04: XAER_NOTA: Unknown XID
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_0';
+INSERT INTO t SET a=0;
+XA END     'trx_0';
+XA PREPARE 'trx_0';
+disconnect conn0;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_1';
+INSERT INTO t SET a=1;
+XA END     'trx_1';
+XA PREPARE 'trx_1';
+disconnect conn1;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_2';
+INSERT INTO t SET a=2;
+XA END     'trx_2';
+XA PREPARE 'trx_2';
+disconnect conn2;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_3';
+INSERT INTO t SET a=3;
+XA END     'trx_3';
+XA PREPARE 'trx_3';
+disconnect conn3;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_4';
+INSERT INTO t SET a=4;
+XA END     'trx_4';
+XA PREPARE 'trx_4';
+disconnect conn4;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_5';
+INSERT INTO t SET a=5;
+XA END     'trx_5';
+XA PREPARE 'trx_5';
+disconnect conn5;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_6';
+INSERT INTO t SET a=6;
+XA END     'trx_6';
+XA PREPARE 'trx_6';
+disconnect conn6;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_7';
+INSERT INTO t SET a=7;
+XA END     'trx_7';
+XA PREPARE 'trx_7';
+disconnect conn7;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_8';
+INSERT INTO t SET a=8;
+XA END     'trx_8';
+XA PREPARE 'trx_8';
+disconnect conn8;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_9';
+INSERT INTO t SET a=9;
+XA END     'trx_9';
+XA PREPARE 'trx_9';
+disconnect conn9;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_10';
+INSERT INTO t SET a=10;
+XA END     'trx_10';
+XA PREPARE 'trx_10';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_11';
+INSERT INTO t SET a=11;
+XA END     'trx_11';
+XA PREPARE 'trx_11';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_12';
+INSERT INTO t SET a=12;
+XA END     'trx_12';
+XA PREPARE 'trx_12';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_13';
+INSERT INTO t SET a=13;
+XA END     'trx_13';
+XA PREPARE 'trx_13';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_14';
+INSERT INTO t SET a=14;
+XA END     'trx_14';
+XA PREPARE 'trx_14';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_15';
+INSERT INTO t SET a=15;
+XA END     'trx_15';
+XA PREPARE 'trx_15';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_16';
+INSERT INTO t SET a=16;
+XA END     'trx_16';
+XA PREPARE 'trx_16';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_17';
+INSERT INTO t SET a=17;
+XA END     'trx_17';
+XA PREPARE 'trx_17';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_18';
+INSERT INTO t SET a=18;
+XA END     'trx_18';
+XA PREPARE 'trx_18';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_19';
+INSERT INTO t SET a=19;
+XA END     'trx_19';
+XA PREPARE 'trx_19';
+connection default;
+KILL CONNECTION CONN_ID;
+connection default;
+XA ROLLBACK 'trx_0';
+XA ROLLBACK 'trx_1';
+XA ROLLBACK 'trx_2';
+XA ROLLBACK 'trx_3';
+XA ROLLBACK 'trx_4';
+XA COMMIT 'trx_5';
+XA COMMIT 'trx_6';
+XA COMMIT 'trx_7';
+XA COMMIT 'trx_8';
+XA COMMIT 'trx_9';
+# restart
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_0';
+INSERT INTO t SET a=0;
+XA END     'new_trx_0';
+XA PREPARE 'new_trx_0';
+disconnect conn_restart_0;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_1';
+INSERT INTO t SET a=1;
+XA END     'new_trx_1';
+XA PREPARE 'new_trx_1';
+disconnect conn_restart_1;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_2';
+INSERT INTO t SET a=2;
+XA END     'new_trx_2';
+XA PREPARE 'new_trx_2';
+disconnect conn_restart_2;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_3';
+INSERT INTO t SET a=3;
+XA END     'new_trx_3';
+XA PREPARE 'new_trx_3';
+disconnect conn_restart_3;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_4';
+INSERT INTO t SET a=4;
+XA END     'new_trx_4';
+XA PREPARE 'new_trx_4';
+disconnect conn_restart_4;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_5';
+INSERT INTO t SET a=5;
+XA END     'new_trx_5';
+XA PREPARE 'new_trx_5';
+disconnect conn_restart_5;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_6';
+INSERT INTO t SET a=6;
+XA END     'new_trx_6';
+XA PREPARE 'new_trx_6';
+disconnect conn_restart_6;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_7';
+INSERT INTO t SET a=7;
+XA END     'new_trx_7';
+XA PREPARE 'new_trx_7';
+disconnect conn_restart_7;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_8';
+INSERT INTO t SET a=8;
+XA END     'new_trx_8';
+XA PREPARE 'new_trx_8';
+disconnect conn_restart_8;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_9';
+INSERT INTO t SET a=9;
+XA END     'new_trx_9';
+XA PREPARE 'new_trx_9';
+disconnect conn_restart_9;
+connection default;
+connection default;
+XA COMMIT  'new_trx_0';
+XA COMMIT  'new_trx_1';
+XA COMMIT  'new_trx_2';
+XA COMMIT  'new_trx_3';
+XA COMMIT  'new_trx_4';
+XA COMMIT  'new_trx_5';
+XA COMMIT  'new_trx_6';
+XA COMMIT  'new_trx_7';
+XA COMMIT  'new_trx_8';
+XA COMMIT  'new_trx_9';
+XA START 'trx_10';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_10';
+XA START 'trx_11';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_11';
+XA START 'trx_12';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_12';
+XA START 'trx_13';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_13';
+XA START 'trx_14';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_14';
+XA START 'trx_15';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_15';
+XA START 'trx_16';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_16';
+XA START 'trx_17';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_17';
+XA START 'trx_18';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_18';
+XA START 'trx_19';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_19';
+SELECT * FROM t;
+a
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+disconnect conn2tmp;
+disconnect conn3tmp;
+disconnect conn2ro;
+disconnect conn3ro;
+disconnect conn2empty;
+disconnect conn3empty;
+connection default;
+XA ROLLBACK 'trx_20';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn19;
+connection default;
+XA ROLLBACK 'trx_19';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn18;
+connection default;
+XA ROLLBACK 'trx_18';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn17;
+connection default;
+XA ROLLBACK 'trx_17';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn16;
+connection default;
+XA ROLLBACK 'trx_16';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn15;
+connection default;
+XA ROLLBACK 'trx_15';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn14;
+connection default;
+XA ROLLBACK 'trx_14';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn13;
+connection default;
+XA ROLLBACK 'trx_13';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn12;
+connection default;
+XA ROLLBACK 'trx_12';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn11;
+connection default;
+XA ROLLBACK 'trx_11';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn10;
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx1tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx1tmp';
+XA PREPARE 'trx1tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx2tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx2tmp';
+XA PREPARE 'trx2tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx3tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx3tmp';
+XA PREPARE 'trx3tmp';
+connection default;
+XA COMMIT 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA ROLLBACK 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA START 'trx1tmp';
+ERROR XAE08: XAER_DUPID: The XID already exists
+connection default;
+*** 3 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1tmp;
+disconnect conn1tmp;
+connection default;
+XA COMMIT 'trx1tmp';
+KILL connection CONN_ID;
+XA COMMIT 'trx3tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1ro';
+SELECT * from t ORDER BY a;
+a
+0
+1
+2
+3
+4
+5
+5
+6
+6
+7
+7
+8
+8
+9
+9
+10
+11
+12
+13
+14
+XA END     'trx1ro';
+XA PREPARE 'trx1ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2ro';
+SELECT * from t ORDER BY a;
+a
+0
+1
+2
+3
+4
+5
+5
+6
+6
+7
+7
+8
+8
+9
+9
+10
+11
+12
+13
+14
+XA END     'trx2ro';
+XA PREPARE 'trx2ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3ro';
+SELECT * from t ORDER BY a;
+a
+0
+1
+2
+3
+4
+5
+5
+6
+6
+7
+7
+8
+8
+9
+9
+10
+11
+12
+13
+14
+XA END     'trx3ro';
+XA PREPARE 'trx3ro';
+connection default;
+*** 4 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1ro;
+disconnect conn1ro;
+connection default;
+XA ROLLBACK 'trx1ro';
+KILL connection CONN_ID;
+XA ROLLBACK 'trx3ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1empty';
+XA END     'trx1empty';
+XA PREPARE 'trx1empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2empty';
+XA END     'trx2empty';
+XA PREPARE 'trx2empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3empty';
+XA END     'trx3empty';
+XA PREPARE 'trx3empty';
+connection default;
+*** 5 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1empty;
+disconnect conn1empty;
+connection default;
+XA COMMIT 'trx1empty';
+KILL connection CONN_ID;
+XA COMMIT 'trx3empty';
+connect conn1$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1unprepared';
+INSERT INTO t set a=0;
+XA END     'trx1unprepared';
+INSERT INTO t set a=0;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+disconnect conn1unprepared;
+connection default;
+XA COMMIT 'trx1unprepared';
+ERROR XAE04: XAER_NOTA: Unknown XID
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_0';
+INSERT INTO t SET a=0;
+XA END     'trx_0';
+XA PREPARE 'trx_0';
+disconnect conn0;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_1';
+INSERT INTO t SET a=1;
+XA END     'trx_1';
+XA PREPARE 'trx_1';
+disconnect conn1;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_2';
+INSERT INTO t SET a=2;
+XA END     'trx_2';
+XA PREPARE 'trx_2';
+disconnect conn2;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_3';
+INSERT INTO t SET a=3;
+XA END     'trx_3';
+XA PREPARE 'trx_3';
+disconnect conn3;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_4';
+INSERT INTO t SET a=4;
+XA END     'trx_4';
+XA PREPARE 'trx_4';
+disconnect conn4;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_5';
+INSERT INTO t SET a=5;
+XA END     'trx_5';
+XA PREPARE 'trx_5';
+disconnect conn5;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_6';
+INSERT INTO t SET a=6;
+XA END     'trx_6';
+XA PREPARE 'trx_6';
+disconnect conn6;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_7';
+INSERT INTO t SET a=7;
+XA END     'trx_7';
+XA PREPARE 'trx_7';
+disconnect conn7;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_8';
+INSERT INTO t SET a=8;
+XA END     'trx_8';
+XA PREPARE 'trx_8';
+disconnect conn8;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_9';
+INSERT INTO t SET a=9;
+XA END     'trx_9';
+XA PREPARE 'trx_9';
+disconnect conn9;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_10';
+INSERT INTO t SET a=10;
+XA END     'trx_10';
+XA PREPARE 'trx_10';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_11';
+INSERT INTO t SET a=11;
+XA END     'trx_11';
+XA PREPARE 'trx_11';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_12';
+INSERT INTO t SET a=12;
+XA END     'trx_12';
+XA PREPARE 'trx_12';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_13';
+INSERT INTO t SET a=13;
+XA END     'trx_13';
+XA PREPARE 'trx_13';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_14';
+INSERT INTO t SET a=14;
+XA END     'trx_14';
+XA PREPARE 'trx_14';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_15';
+INSERT INTO t SET a=15;
+XA END     'trx_15';
+XA PREPARE 'trx_15';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_16';
+INSERT INTO t SET a=16;
+XA END     'trx_16';
+XA PREPARE 'trx_16';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_17';
+INSERT INTO t SET a=17;
+XA END     'trx_17';
+XA PREPARE 'trx_17';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_18';
+INSERT INTO t SET a=18;
+XA END     'trx_18';
+XA PREPARE 'trx_18';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_19';
+INSERT INTO t SET a=19;
+XA END     'trx_19';
+XA PREPARE 'trx_19';
+connection default;
+KILL CONNECTION CONN_ID;
+connection default;
+XA ROLLBACK 'trx_0';
+XA ROLLBACK 'trx_1';
+XA ROLLBACK 'trx_2';
+XA ROLLBACK 'trx_3';
+XA ROLLBACK 'trx_4';
+XA COMMIT 'trx_5';
+XA COMMIT 'trx_6';
+XA COMMIT 'trx_7';
+XA COMMIT 'trx_8';
+XA COMMIT 'trx_9';
+# Kill and restart
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_0';
+INSERT INTO t SET a=0;
+XA END     'new_trx_0';
+XA PREPARE 'new_trx_0';
+disconnect conn_restart_0;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_1';
+INSERT INTO t SET a=1;
+XA END     'new_trx_1';
+XA PREPARE 'new_trx_1';
+disconnect conn_restart_1;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_2';
+INSERT INTO t SET a=2;
+XA END     'new_trx_2';
+XA PREPARE 'new_trx_2';
+disconnect conn_restart_2;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_3';
+INSERT INTO t SET a=3;
+XA END     'new_trx_3';
+XA PREPARE 'new_trx_3';
+disconnect conn_restart_3;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_4';
+INSERT INTO t SET a=4;
+XA END     'new_trx_4';
+XA PREPARE 'new_trx_4';
+disconnect conn_restart_4;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_5';
+INSERT INTO t SET a=5;
+XA END     'new_trx_5';
+XA PREPARE 'new_trx_5';
+disconnect conn_restart_5;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_6';
+INSERT INTO t SET a=6;
+XA END     'new_trx_6';
+XA PREPARE 'new_trx_6';
+disconnect conn_restart_6;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_7';
+INSERT INTO t SET a=7;
+XA END     'new_trx_7';
+XA PREPARE 'new_trx_7';
+disconnect conn_restart_7;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_8';
+INSERT INTO t SET a=8;
+XA END     'new_trx_8';
+XA PREPARE 'new_trx_8';
+disconnect conn_restart_8;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_9';
+INSERT INTO t SET a=9;
+XA END     'new_trx_9';
+XA PREPARE 'new_trx_9';
+disconnect conn_restart_9;
+connection default;
+connection default;
+XA COMMIT  'new_trx_0';
+XA COMMIT  'new_trx_1';
+XA COMMIT  'new_trx_2';
+XA COMMIT  'new_trx_3';
+XA COMMIT  'new_trx_4';
+XA COMMIT  'new_trx_5';
+XA COMMIT  'new_trx_6';
+XA COMMIT  'new_trx_7';
+XA COMMIT  'new_trx_8';
+XA COMMIT  'new_trx_9';
+XA START 'trx_10';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_10';
+XA START 'trx_11';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_11';
+XA START 'trx_12';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_12';
+XA START 'trx_13';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_13';
+XA START 'trx_14';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_14';
+XA START 'trx_15';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_15';
+XA START 'trx_16';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_16';
+XA START 'trx_17';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_17';
+XA START 'trx_18';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_18';
+XA START 'trx_19';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_19';
+SELECT * FROM t;
+a
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+disconnect conn2tmp;
+disconnect conn3tmp;
+disconnect conn2ro;
+disconnect conn3ro;
+disconnect conn2empty;
+disconnect conn3empty;
+connection default;
+XA ROLLBACK 'trx_20';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn19;
+connection default;
+XA ROLLBACK 'trx_19';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn18;
+connection default;
+XA ROLLBACK 'trx_18';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn17;
+connection default;
+XA ROLLBACK 'trx_17';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn16;
+connection default;
+XA ROLLBACK 'trx_16';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn15;
+connection default;
+XA ROLLBACK 'trx_15';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn14;
+connection default;
+XA ROLLBACK 'trx_14';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn13;
+connection default;
+XA ROLLBACK 'trx_13';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn12;
+connection default;
+XA ROLLBACK 'trx_12';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn11;
+connection default;
+XA ROLLBACK 'trx_11';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn10;
+connection default;
+XA START   'one_phase_trx_0';
+INSERT INTO t SET a=0;
+XA END     'one_phase_trx_0';
+XA COMMIT  'one_phase_trx_0' ONE PHASE;
+XA START   'one_phase_trx_1';
+INSERT INTO t SET a=1;
+XA END     'one_phase_trx_1';
+XA COMMIT  'one_phase_trx_1' ONE PHASE;
+XA START   'one_phase_trx_2';
+INSERT INTO t SET a=2;
+XA END     'one_phase_trx_2';
+XA COMMIT  'one_phase_trx_2' ONE PHASE;
+XA START   'one_phase_trx_3';
+INSERT INTO t SET a=3;
+XA END     'one_phase_trx_3';
+XA COMMIT  'one_phase_trx_3' ONE PHASE;
+XA START   'one_phase_trx_4';
+INSERT INTO t SET a=4;
+XA END     'one_phase_trx_4';
+XA COMMIT  'one_phase_trx_4' ONE PHASE;
+SELECT SUM(a) FROM t;
+SUM(a)
+290
+DROP TABLE t;
+DROP VIEW v_processlist;
+include/show_binlog_events.inc
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_processlist` AS SELECT * FROM performance_schema.threads where type = 'FOREGROUND'
+master-bin.000001	#	Gtid	#	#	BEGIN GTID #-#-#
+master-bin.000001	#	Query	#	#	use `mtr`; INSERT INTO test_suppressions (pattern) VALUES ( NAME_CONST('pattern',_latin1'Found 10 prepared XA transactions' COLLATE 'latin1_swedish_ci'))
+master-bin.000001	#	Query	#	#	COMMIT
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; CREATE TABLE t (a INT) ENGINE=innodb
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f30',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=0
+master-bin.000001	#	Query	#	#	XA END X'7472785f30',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f30',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f31',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=1
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f31',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f31',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f32',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=2
+master-bin.000001	#	Query	#	#	XA END X'7472785f32',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f32',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f33',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=3
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f33',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f33',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f34',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=4
+master-bin.000001	#	Query	#	#	XA END X'7472785f34',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f34',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f35',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=5
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f35',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f35',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f36',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=6
+master-bin.000001	#	Query	#	#	XA END X'7472785f36',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f36',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f37',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=7
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f37',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f37',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f38',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=8
+master-bin.000001	#	Query	#	#	XA END X'7472785f38',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f38',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f39',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=9
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f39',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f39',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3130',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=10
+master-bin.000001	#	Query	#	#	XA END X'7472785f3130',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3130',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3131',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=11
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f3131',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3131',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3132',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=12
+master-bin.000001	#	Query	#	#	XA END X'7472785f3132',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3132',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3133',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=13
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f3133',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3133',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3134',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=14
+master-bin.000001	#	Query	#	#	XA END X'7472785f3134',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3134',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3135',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=15
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f3135',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3135',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3136',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=16
+master-bin.000001	#	Query	#	#	XA END X'7472785f3136',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3136',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3137',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=17
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f3137',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3137',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3138',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=18
+master-bin.000001	#	Query	#	#	XA END X'7472785f3138',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3138',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3139',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=19
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f3139',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3139',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA ROLLBACK X'7472785f30',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA ROLLBACK X'7472785f31',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA ROLLBACK X'7472785f32',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA ROLLBACK X'7472785f33',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA ROLLBACK X'7472785f34',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'7472785f35',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'7472785f36',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'7472785f37',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'7472785f38',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'7472785f39',X'',1
+master-bin.000001	#	Stop	#	#	
+All transactions must be completed, to empty-list the following:
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
diff --git a/mysql-test/suite/binlog/r/binlog_xa_prepared_disconnect.result b/mysql-test/suite/binlog/r/binlog_xa_prepared_disconnect.result
new file mode 100644
index 00000000000..9fda8ab3143
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_xa_prepared_disconnect.result
@@ -0,0 +1,1176 @@
+connection default;
+RESET MASTER;
+CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
+call mtr.add_suppression("Found 10 prepared XA transactions");
+CREATE TABLE t (a INT) ENGINE=innodb;
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx1tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx1tmp';
+XA PREPARE 'trx1tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx2tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx2tmp';
+XA PREPARE 'trx2tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx3tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx3tmp';
+XA PREPARE 'trx3tmp';
+connection default;
+XA COMMIT 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA ROLLBACK 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA START 'trx1tmp';
+ERROR XAE08: XAER_DUPID: The XID already exists
+connection default;
+*** 3 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1tmp;
+disconnect conn1tmp;
+connection default;
+XA COMMIT 'trx1tmp';
+KILL connection CONN_ID;
+XA COMMIT 'trx3tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1ro';
+SELECT * from t ORDER BY a;
+a
+XA END     'trx1ro';
+XA PREPARE 'trx1ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2ro';
+SELECT * from t ORDER BY a;
+a
+XA END     'trx2ro';
+XA PREPARE 'trx2ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3ro';
+SELECT * from t ORDER BY a;
+a
+XA END     'trx3ro';
+XA PREPARE 'trx3ro';
+connection default;
+*** 4 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1ro;
+disconnect conn1ro;
+connection default;
+XA ROLLBACK 'trx1ro';
+KILL connection CONN_ID;
+XA ROLLBACK 'trx3ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1empty';
+XA END     'trx1empty';
+XA PREPARE 'trx1empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2empty';
+XA END     'trx2empty';
+XA PREPARE 'trx2empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3empty';
+XA END     'trx3empty';
+XA PREPARE 'trx3empty';
+connection default;
+*** 5 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1empty;
+disconnect conn1empty;
+connection default;
+XA COMMIT 'trx1empty';
+KILL connection CONN_ID;
+XA COMMIT 'trx3empty';
+connect conn1$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1unprepared';
+INSERT INTO t set a=0;
+XA END     'trx1unprepared';
+INSERT INTO t set a=0;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+disconnect conn1unprepared;
+connection default;
+XA COMMIT 'trx1unprepared';
+ERROR XAE04: XAER_NOTA: Unknown XID
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_0';
+INSERT INTO t SET a=0;
+XA END     'trx_0';
+XA PREPARE 'trx_0';
+disconnect conn0;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_1';
+INSERT INTO t SET a=1;
+XA END     'trx_1';
+XA PREPARE 'trx_1';
+disconnect conn1;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_2';
+INSERT INTO t SET a=2;
+XA END     'trx_2';
+XA PREPARE 'trx_2';
+disconnect conn2;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_3';
+INSERT INTO t SET a=3;
+XA END     'trx_3';
+XA PREPARE 'trx_3';
+disconnect conn3;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_4';
+INSERT INTO t SET a=4;
+XA END     'trx_4';
+XA PREPARE 'trx_4';
+disconnect conn4;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_5';
+INSERT INTO t SET a=5;
+XA END     'trx_5';
+XA PREPARE 'trx_5';
+disconnect conn5;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_6';
+INSERT INTO t SET a=6;
+XA END     'trx_6';
+XA PREPARE 'trx_6';
+disconnect conn6;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_7';
+INSERT INTO t SET a=7;
+XA END     'trx_7';
+XA PREPARE 'trx_7';
+disconnect conn7;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_8';
+INSERT INTO t SET a=8;
+XA END     'trx_8';
+XA PREPARE 'trx_8';
+disconnect conn8;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_9';
+INSERT INTO t SET a=9;
+XA END     'trx_9';
+XA PREPARE 'trx_9';
+disconnect conn9;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_10';
+INSERT INTO t SET a=10;
+XA END     'trx_10';
+XA PREPARE 'trx_10';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_11';
+INSERT INTO t SET a=11;
+XA END     'trx_11';
+XA PREPARE 'trx_11';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_12';
+INSERT INTO t SET a=12;
+XA END     'trx_12';
+XA PREPARE 'trx_12';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_13';
+INSERT INTO t SET a=13;
+XA END     'trx_13';
+XA PREPARE 'trx_13';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_14';
+INSERT INTO t SET a=14;
+XA END     'trx_14';
+XA PREPARE 'trx_14';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_15';
+INSERT INTO t SET a=15;
+XA END     'trx_15';
+XA PREPARE 'trx_15';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_16';
+INSERT INTO t SET a=16;
+XA END     'trx_16';
+XA PREPARE 'trx_16';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_17';
+INSERT INTO t SET a=17;
+XA END     'trx_17';
+XA PREPARE 'trx_17';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_18';
+INSERT INTO t SET a=18;
+XA END     'trx_18';
+XA PREPARE 'trx_18';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_19';
+INSERT INTO t SET a=19;
+XA END     'trx_19';
+XA PREPARE 'trx_19';
+connection default;
+KILL CONNECTION CONN_ID;
+connection default;
+XA ROLLBACK 'trx_0';
+XA ROLLBACK 'trx_1';
+XA ROLLBACK 'trx_2';
+XA ROLLBACK 'trx_3';
+XA ROLLBACK 'trx_4';
+XA COMMIT 'trx_5';
+XA COMMIT 'trx_6';
+XA COMMIT 'trx_7';
+XA COMMIT 'trx_8';
+XA COMMIT 'trx_9';
+# restart
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_0';
+INSERT INTO t SET a=0;
+XA END     'new_trx_0';
+XA PREPARE 'new_trx_0';
+disconnect conn_restart_0;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_1';
+INSERT INTO t SET a=1;
+XA END     'new_trx_1';
+XA PREPARE 'new_trx_1';
+disconnect conn_restart_1;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_2';
+INSERT INTO t SET a=2;
+XA END     'new_trx_2';
+XA PREPARE 'new_trx_2';
+disconnect conn_restart_2;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_3';
+INSERT INTO t SET a=3;
+XA END     'new_trx_3';
+XA PREPARE 'new_trx_3';
+disconnect conn_restart_3;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_4';
+INSERT INTO t SET a=4;
+XA END     'new_trx_4';
+XA PREPARE 'new_trx_4';
+disconnect conn_restart_4;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_5';
+INSERT INTO t SET a=5;
+XA END     'new_trx_5';
+XA PREPARE 'new_trx_5';
+disconnect conn_restart_5;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_6';
+INSERT INTO t SET a=6;
+XA END     'new_trx_6';
+XA PREPARE 'new_trx_6';
+disconnect conn_restart_6;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_7';
+INSERT INTO t SET a=7;
+XA END     'new_trx_7';
+XA PREPARE 'new_trx_7';
+disconnect conn_restart_7;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_8';
+INSERT INTO t SET a=8;
+XA END     'new_trx_8';
+XA PREPARE 'new_trx_8';
+disconnect conn_restart_8;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_9';
+INSERT INTO t SET a=9;
+XA END     'new_trx_9';
+XA PREPARE 'new_trx_9';
+disconnect conn_restart_9;
+connection default;
+connection default;
+XA COMMIT  'new_trx_0';
+XA COMMIT  'new_trx_1';
+XA COMMIT  'new_trx_2';
+XA COMMIT  'new_trx_3';
+XA COMMIT  'new_trx_4';
+XA COMMIT  'new_trx_5';
+XA COMMIT  'new_trx_6';
+XA COMMIT  'new_trx_7';
+XA COMMIT  'new_trx_8';
+XA COMMIT  'new_trx_9';
+XA START 'trx_10';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_10';
+XA START 'trx_11';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_11';
+XA START 'trx_12';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_12';
+XA START 'trx_13';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_13';
+XA START 'trx_14';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_14';
+XA START 'trx_15';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_15';
+XA START 'trx_16';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_16';
+XA START 'trx_17';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_17';
+XA START 'trx_18';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_18';
+XA START 'trx_19';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_19';
+SELECT * FROM t;
+a
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+disconnect conn2tmp;
+disconnect conn3tmp;
+disconnect conn2ro;
+disconnect conn3ro;
+disconnect conn2empty;
+disconnect conn3empty;
+connection default;
+XA ROLLBACK 'trx_20';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn19;
+connection default;
+XA ROLLBACK 'trx_19';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn18;
+connection default;
+XA ROLLBACK 'trx_18';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn17;
+connection default;
+XA ROLLBACK 'trx_17';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn16;
+connection default;
+XA ROLLBACK 'trx_16';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn15;
+connection default;
+XA ROLLBACK 'trx_15';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn14;
+connection default;
+XA ROLLBACK 'trx_14';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn13;
+connection default;
+XA ROLLBACK 'trx_13';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn12;
+connection default;
+XA ROLLBACK 'trx_12';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn11;
+connection default;
+XA ROLLBACK 'trx_11';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn10;
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx1tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx1tmp';
+XA PREPARE 'trx1tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx2tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx2tmp';
+XA PREPARE 'trx2tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@sql_log_bin = OFF;
+CREATE TEMPORARY TABLE tmp1 (a int) ENGINE=innodb;
+XA START   'trx3tmp';
+INSERT INTO tmp1 SET a=1;
+XA END     'trx3tmp';
+XA PREPARE 'trx3tmp';
+connection default;
+XA COMMIT 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA ROLLBACK 'trx1tmp';
+ERROR XAE04: XAER_NOTA: Unknown XID
+XA START 'trx1tmp';
+ERROR XAE08: XAER_DUPID: The XID already exists
+connection default;
+*** 3 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1tmp;
+disconnect conn1tmp;
+connection default;
+XA COMMIT 'trx1tmp';
+KILL connection CONN_ID;
+XA COMMIT 'trx3tmp';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1ro';
+SELECT * from t ORDER BY a;
+a
+0
+1
+2
+3
+4
+5
+5
+6
+6
+7
+7
+8
+8
+9
+9
+10
+11
+12
+13
+14
+XA END     'trx1ro';
+XA PREPARE 'trx1ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2ro';
+SELECT * from t ORDER BY a;
+a
+0
+1
+2
+3
+4
+5
+5
+6
+6
+7
+7
+8
+8
+9
+9
+10
+11
+12
+13
+14
+XA END     'trx2ro';
+XA PREPARE 'trx2ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3ro';
+SELECT * from t ORDER BY a;
+a
+0
+1
+2
+3
+4
+5
+5
+6
+6
+7
+7
+8
+8
+9
+9
+10
+11
+12
+13
+14
+XA END     'trx3ro';
+XA PREPARE 'trx3ro';
+connection default;
+*** 4 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1ro;
+disconnect conn1ro;
+connection default;
+XA ROLLBACK 'trx1ro';
+KILL connection CONN_ID;
+XA ROLLBACK 'trx3ro';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1empty';
+XA END     'trx1empty';
+XA PREPARE 'trx1empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx2empty';
+XA END     'trx2empty';
+XA PREPARE 'trx2empty';
+connect  conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx3empty';
+XA END     'trx3empty';
+XA PREPARE 'trx3empty';
+connection default;
+*** 5 prepared transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+1	LEN1	LEN2	TRX_N
+connection conn1empty;
+disconnect conn1empty;
+connection default;
+XA COMMIT 'trx1empty';
+KILL connection CONN_ID;
+XA COMMIT 'trx3empty';
+connect conn1$type, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'trx1unprepared';
+INSERT INTO t set a=0;
+XA END     'trx1unprepared';
+INSERT INTO t set a=0;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+XA START 'trx1unprepared';
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
+disconnect conn1unprepared;
+connection default;
+XA COMMIT 'trx1unprepared';
+ERROR XAE04: XAER_NOTA: Unknown XID
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_0';
+INSERT INTO t SET a=0;
+XA END     'trx_0';
+XA PREPARE 'trx_0';
+disconnect conn0;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_1';
+INSERT INTO t SET a=1;
+XA END     'trx_1';
+XA PREPARE 'trx_1';
+disconnect conn1;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_2';
+INSERT INTO t SET a=2;
+XA END     'trx_2';
+XA PREPARE 'trx_2';
+disconnect conn2;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_3';
+INSERT INTO t SET a=3;
+XA END     'trx_3';
+XA PREPARE 'trx_3';
+disconnect conn3;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_4';
+INSERT INTO t SET a=4;
+XA END     'trx_4';
+XA PREPARE 'trx_4';
+disconnect conn4;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_5';
+INSERT INTO t SET a=5;
+XA END     'trx_5';
+XA PREPARE 'trx_5';
+disconnect conn5;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_6';
+INSERT INTO t SET a=6;
+XA END     'trx_6';
+XA PREPARE 'trx_6';
+disconnect conn6;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_7';
+INSERT INTO t SET a=7;
+XA END     'trx_7';
+XA PREPARE 'trx_7';
+disconnect conn7;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_8';
+INSERT INTO t SET a=8;
+XA END     'trx_8';
+XA PREPARE 'trx_8';
+disconnect conn8;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_9';
+INSERT INTO t SET a=9;
+XA END     'trx_9';
+XA PREPARE 'trx_9';
+disconnect conn9;
+connection default;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_10';
+INSERT INTO t SET a=10;
+XA END     'trx_10';
+XA PREPARE 'trx_10';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_11';
+INSERT INTO t SET a=11;
+XA END     'trx_11';
+XA PREPARE 'trx_11';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_12';
+INSERT INTO t SET a=12;
+XA END     'trx_12';
+XA PREPARE 'trx_12';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_13';
+INSERT INTO t SET a=13;
+XA END     'trx_13';
+XA PREPARE 'trx_13';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_14';
+INSERT INTO t SET a=14;
+XA END     'trx_14';
+XA PREPARE 'trx_14';
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_15';
+INSERT INTO t SET a=15;
+XA END     'trx_15';
+XA PREPARE 'trx_15';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_16';
+INSERT INTO t SET a=16;
+XA END     'trx_16';
+XA PREPARE 'trx_16';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_17';
+INSERT INTO t SET a=17;
+XA END     'trx_17';
+XA PREPARE 'trx_17';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+XA START   'trx_18';
+INSERT INTO t SET a=18;
+XA END     'trx_18';
+XA PREPARE 'trx_18';
+connection default;
+KILL CONNECTION CONN_ID;
+connect  conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@binlog_format = STATEMENT;
+SET @@binlog_format = ROW;
+XA START   'trx_19';
+INSERT INTO t SET a=19;
+XA END     'trx_19';
+XA PREPARE 'trx_19';
+connection default;
+KILL CONNECTION CONN_ID;
+connection default;
+XA ROLLBACK 'trx_0';
+XA ROLLBACK 'trx_1';
+XA ROLLBACK 'trx_2';
+XA ROLLBACK 'trx_3';
+XA ROLLBACK 'trx_4';
+XA COMMIT 'trx_5';
+XA COMMIT 'trx_6';
+XA COMMIT 'trx_7';
+XA COMMIT 'trx_8';
+XA COMMIT 'trx_9';
+# Kill and restart
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_0';
+INSERT INTO t SET a=0;
+XA END     'new_trx_0';
+XA PREPARE 'new_trx_0';
+disconnect conn_restart_0;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_1';
+INSERT INTO t SET a=1;
+XA END     'new_trx_1';
+XA PREPARE 'new_trx_1';
+disconnect conn_restart_1;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_2';
+INSERT INTO t SET a=2;
+XA END     'new_trx_2';
+XA PREPARE 'new_trx_2';
+disconnect conn_restart_2;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_3';
+INSERT INTO t SET a=3;
+XA END     'new_trx_3';
+XA PREPARE 'new_trx_3';
+disconnect conn_restart_3;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_4';
+INSERT INTO t SET a=4;
+XA END     'new_trx_4';
+XA PREPARE 'new_trx_4';
+disconnect conn_restart_4;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_5';
+INSERT INTO t SET a=5;
+XA END     'new_trx_5';
+XA PREPARE 'new_trx_5';
+disconnect conn_restart_5;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_6';
+INSERT INTO t SET a=6;
+XA END     'new_trx_6';
+XA PREPARE 'new_trx_6';
+disconnect conn_restart_6;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_7';
+INSERT INTO t SET a=7;
+XA END     'new_trx_7';
+XA PREPARE 'new_trx_7';
+disconnect conn_restart_7;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_8';
+INSERT INTO t SET a=8;
+XA END     'new_trx_8';
+XA PREPARE 'new_trx_8';
+disconnect conn_restart_8;
+connection default;
+connect  conn_restart_$k, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START   'new_trx_9';
+INSERT INTO t SET a=9;
+XA END     'new_trx_9';
+XA PREPARE 'new_trx_9';
+disconnect conn_restart_9;
+connection default;
+connection default;
+XA COMMIT  'new_trx_0';
+XA COMMIT  'new_trx_1';
+XA COMMIT  'new_trx_2';
+XA COMMIT  'new_trx_3';
+XA COMMIT  'new_trx_4';
+XA COMMIT  'new_trx_5';
+XA COMMIT  'new_trx_6';
+XA COMMIT  'new_trx_7';
+XA COMMIT  'new_trx_8';
+XA COMMIT  'new_trx_9';
+XA START 'trx_10';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_10';
+XA START 'trx_11';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_11';
+XA START 'trx_12';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_12';
+XA START 'trx_13';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_13';
+XA START 'trx_14';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA COMMIT 'trx_14';
+XA START 'trx_15';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_15';
+XA START 'trx_16';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_16';
+XA START 'trx_17';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_17';
+XA START 'trx_18';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_18';
+XA START 'trx_19';
+ERROR XAE08: XAER_DUPID: The XID already exists
+XA ROLLBACK 'trx_19';
+SELECT * FROM t;
+a
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+disconnect conn2tmp;
+disconnect conn3tmp;
+disconnect conn2ro;
+disconnect conn3ro;
+disconnect conn2empty;
+disconnect conn3empty;
+connection default;
+XA ROLLBACK 'trx_20';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn19;
+connection default;
+XA ROLLBACK 'trx_19';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn18;
+connection default;
+XA ROLLBACK 'trx_18';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn17;
+connection default;
+XA ROLLBACK 'trx_17';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn16;
+connection default;
+XA ROLLBACK 'trx_16';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn15;
+connection default;
+XA ROLLBACK 'trx_15';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn14;
+connection default;
+XA ROLLBACK 'trx_14';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn13;
+connection default;
+XA ROLLBACK 'trx_13';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn12;
+connection default;
+XA ROLLBACK 'trx_12';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn11;
+connection default;
+XA ROLLBACK 'trx_11';
+ERROR XAE04: XAER_NOTA: Unknown XID
+disconnect conn10;
+connection default;
+XA START   'one_phase_trx_0';
+INSERT INTO t SET a=0;
+XA END     'one_phase_trx_0';
+XA COMMIT  'one_phase_trx_0' ONE PHASE;
+XA START   'one_phase_trx_1';
+INSERT INTO t SET a=1;
+XA END     'one_phase_trx_1';
+XA COMMIT  'one_phase_trx_1' ONE PHASE;
+XA START   'one_phase_trx_2';
+INSERT INTO t SET a=2;
+XA END     'one_phase_trx_2';
+XA COMMIT  'one_phase_trx_2' ONE PHASE;
+XA START   'one_phase_trx_3';
+INSERT INTO t SET a=3;
+XA END     'one_phase_trx_3';
+XA COMMIT  'one_phase_trx_3' ONE PHASE;
+XA START   'one_phase_trx_4';
+INSERT INTO t SET a=4;
+XA END     'one_phase_trx_4';
+XA COMMIT  'one_phase_trx_4' ONE PHASE;
+SELECT SUM(a) FROM t;
+SUM(a)
+290
+DROP TABLE t;
+DROP VIEW v_processlist;
+include/show_binlog_events.inc
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_processlist` AS SELECT * FROM performance_schema.threads where type = 'FOREGROUND'
+master-bin.000001	#	Gtid	#	#	BEGIN GTID #-#-#
+master-bin.000001	#	Query	#	#	use `mtr`; INSERT INTO test_suppressions (pattern) VALUES ( NAME_CONST('pattern',_latin1'Found 10 prepared XA transactions' COLLATE 'latin1_swedish_ci'))
+master-bin.000001	#	Query	#	#	COMMIT
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; CREATE TABLE t (a INT) ENGINE=innodb
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f30',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=0
+master-bin.000001	#	Query	#	#	XA END X'7472785f30',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f30',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f31',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=1
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f31',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f31',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f32',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=2
+master-bin.000001	#	Query	#	#	XA END X'7472785f32',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f32',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f33',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=3
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f33',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f33',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f34',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=4
+master-bin.000001	#	Query	#	#	XA END X'7472785f34',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f34',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f35',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=5
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f35',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f35',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f36',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=6
+master-bin.000001	#	Query	#	#	XA END X'7472785f36',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f36',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f37',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=7
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f37',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f37',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f38',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=8
+master-bin.000001	#	Query	#	#	XA END X'7472785f38',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f38',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f39',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=9
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f39',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f39',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3130',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=10
+master-bin.000001	#	Query	#	#	XA END X'7472785f3130',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3130',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3131',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=11
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f3131',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3131',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3132',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=12
+master-bin.000001	#	Query	#	#	XA END X'7472785f3132',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3132',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3133',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=13
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f3133',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3133',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3134',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=14
+master-bin.000001	#	Query	#	#	XA END X'7472785f3134',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3134',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3135',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=15
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f3135',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3135',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3136',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=16
+master-bin.000001	#	Query	#	#	XA END X'7472785f3136',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3136',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3137',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=17
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f3137',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3137',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3138',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t SET a=18
+master-bin.000001	#	Query	#	#	XA END X'7472785f3138',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3138',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'7472785f3139',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO t SET a=19
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'7472785f3139',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'7472785f3139',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA ROLLBACK X'7472785f30',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA ROLLBACK X'7472785f31',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA ROLLBACK X'7472785f32',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA ROLLBACK X'7472785f33',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA ROLLBACK X'7472785f34',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'7472785f35',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'7472785f36',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'7472785f37',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'7472785f38',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'7472785f39',X'',1
+master-bin.000001	#	Stop	#	#	
+All transactions must be completed, to empty-list the following:
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
diff --git a/mysql-test/suite/binlog/t/binlog_xa_checkpoint.test b/mysql-test/suite/binlog/t/binlog_xa_checkpoint.test
new file mode 100644
index 00000000000..b208d02cf2a
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_xa_checkpoint.test
@@ -0,0 +1,57 @@
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/have_binlog_format_row.inc
+
+RESET MASTER;
+
+CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb;
+
+# Test that
+# 1. XA PREPARE is binlogged before the XA has been prepared in Engine
+# 2. While XA PREPARE already binlogged in an old binlog file which has been rotated,
+#    Binlog checkpoint is not generated for the latest log until
+#    XA PREPARE returns, e.g OK to the client.
+
+
+# con1 will hang before doing commit checkpoint, blocking RESET MASTER.
+connect(con1,localhost,root,,);
+SET DEBUG_SYNC= "at_unlog_xa_prepare SIGNAL con1_ready WAIT_FOR con1_go";
+XA START '1';
+INSERT INTO t1 SET a=1;
+XA END '1';
+--send XA PREPARE '1';
+
+
+connection default;
+SET DEBUG_SYNC= "now WAIT_FOR con1_ready";
+FLUSH LOGS;
+FLUSH LOGS;
+FLUSH LOGS;
+
+--source include/show_binary_logs.inc
+--let $binlog_file= master-bin.000004
+--let $binlog_start= 4
+--source include/show_binlog_events.inc
+
+SET DEBUG_SYNC= "now SIGNAL con1_go";
+
+connection con1;
+reap;
+--echo *** master-bin.000004 checkpoint must show up now ***
+--source include/wait_for_binlog_checkpoint.inc
+
+# Todo: think about the error code returned, move to an appropriate test, or remove
+# connection default;
+#--error 1399
+# DROP TABLE t1;
+
+connection con1;
+XA ROLLBACK '1';
+SET debug_sync = 'reset';
+
+# Clean up.
+connection default;
+
+DROP TABLE t1;
+SET debug_sync = 'reset';
diff --git a/mysql-test/suite/binlog/t/binlog_xa_prepared.inc b/mysql-test/suite/binlog/t/binlog_xa_prepared.inc
new file mode 100644
index 00000000000..b6306791cf4
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_xa_prepared.inc
@@ -0,0 +1,102 @@
+--source include/have_innodb.inc
+--source include/have_perfschema.inc
+#
+# The test verifies binlogging of XA transaction and state of prepared XA
+# as far as binlog is concerned.
+#
+# The prepared XA transactions can be disconnected from the client,
+# discovered from another connection and commited or rolled back
+# later. They also survive the server restart.  The test runs two
+# loops each consisting of prepared XA:s generation, their
+# manipulation and a server restart followed with survived XA:s
+# completion.
+#
+# Prepared XA can't get available to an external connection
+# until connection that either leaves actively or is killed
+# has completed a necessary part of its cleanup.
+# Selecting from P_S.threads provides a method to learn that.
+#
+# Total number of connection each performing one insert into table
+--let $conn_number=20
+# Number of rollbacks and commits from either side of the server restart
+--let $rollback_number=5
+--let $commit_number=5
+# Number of transactions that are terminated before server restarts
+--let $term_number=`SELECT $rollback_number + $commit_number`
+# Instead of disconnect make some connections killed when their
+# transactions got prepared.
+--let $killed_number=5
+# make some connections disconnected by shutdown rather than actively
+--let $server_disconn_number=5
+--let $prepared_at_server_restart = `SELECT $conn_number - $term_number`
+# number a "warmup" connection after server restart, they all commit
+--let $post_restart_conn_number=10
+
+# Counter to be used in GTID consistency check.
+# It's incremented per each non-XA transaction commit.
+# Local to this file variable to control one-phase commit loop
+--let $one_phase_number = 5
+
+--connection default
+
+# Remove possibly preceeding binlogs and clear initialization time
+# GTID executed info. In the following all transactions are counted
+# to conduct verification at the end of the test.
+if (`SELECT @@global.log_bin`)
+{
+  RESET MASTER;
+}
+
+# Disconected and follower threads need synchronization
+CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
+
+--eval call mtr.add_suppression("Found $prepared_at_server_restart prepared XA transactions")
+
+CREATE TABLE t (a INT) ENGINE=innodb;
+
+# Counter is incremented at the end of post restart to
+# reflect number of loops done in correctness computation.
+--let $restart_number = 0
+--let $how_to_restart=restart_mysqld.inc
+--source suite/binlog/include/binlog_xa_prepared_do_and_restart.inc
+
+--let $how_to_restart=kill_and_restart_mysqld.inc
+--source suite/binlog/include/binlog_xa_prepared_do_and_restart.inc
+
+--connection default
+
+# Few xs that commit in one phase, not subject to the server restart
+# nor reconnect.
+# This piece of test is related to mysqlbinlog recovery examine below.
+--let $k = 0
+while ($k < $one_phase_number)
+{
+    --eval XA START   'one_phase_trx_$k'
+    --eval INSERT INTO t SET a=$k
+    --eval XA END     'one_phase_trx_$k'
+    --eval XA COMMIT  'one_phase_trx_$k' ONE PHASE
+
+    --inc $k
+}
+
+SELECT SUM(a) FROM t;
+DROP TABLE t;
+DROP VIEW v_processlist;
+
+let $outfile= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql;
+if (`SELECT @@global.log_bin`)
+{
+  # Recording proper samples of binlogged prepared XA:s
+  --source include/show_binlog_events.inc
+  --exec $MYSQL_BINLOG -R --to-last-log master-bin.000001 > $outfile
+}
+
+--echo All transactions must be completed, to empty-list the following:
+XA RECOVER;
+
+if (`SELECT @@global.log_bin`)
+{
+  --exec $MYSQL test < $outfile
+  --remove_file $outfile
+  XA RECOVER;
+}
diff --git a/mysql-test/suite/binlog/t/binlog_xa_prepared_disconnect.test b/mysql-test/suite/binlog/t/binlog_xa_prepared_disconnect.test
new file mode 100644
index 00000000000..2a3184030cf
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_xa_prepared_disconnect.test
@@ -0,0 +1,11 @@
+###############################################################################
+# Bug#12161 Xa recovery and client disconnection
+# Testing new server options and binary logging prepared XA transaction.
+###############################################################################
+
+#
+# MIXED mode is chosen because formats are varied inside the sourced tests.
+#
+--source include/have_binlog_format_mixed.inc
+
+--source suite/binlog/t/binlog_xa_prepared.inc
diff --git a/mysql-test/suite/rpl/include/rpl_xa_mixed_engines.inc b/mysql-test/suite/rpl/include/rpl_xa_mixed_engines.inc
new file mode 100644
index 00000000000..0707a04090a
--- /dev/null
+++ b/mysql-test/suite/rpl/include/rpl_xa_mixed_engines.inc
@@ -0,0 +1,183 @@
+#
+# The test file is invoked from rpl.rpl_xa_survive_disconnect_mixed_engines
+#
+# The test file is orginized as three sections: setup, run and cleanup.
+# The main logics is resided in the run section which generates
+# three types of XA transaction: two kinds of mixed and one on non-transactional
+# table.
+#
+# param $command          one of three of: 'setup', 'run' or 'cleanup'
+# param $xa_terminate     how to conclude: 'XA COMMIT' or 'XA ROLLBACK'
+# param $one_phase        'one_phase' can be opted with XA COMMIT above
+# param $xa_prepare_opt   '1' or empty can be opted to test with and without XA PREPARE
+# param $xid              arbitrary name for xa trx, defaults to 'xa_trx'
+# Note '' is merely to underline, not a part of the value.
+#
+
+if ($command == setup)
+{
+  # Test randomizes the following variable's value:
+  SET @@session.binlog_direct_non_transactional_updates := if(floor(rand()*10)%2,'ON','OFF');
+  CREATE TABLE t (a INT) ENGINE=innodb;
+  CREATE TABLE tm (a INT) ENGINE=myisam;
+}
+if (!$xid)
+{
+  --let $xid=xa_trx
+}
+if ($command == run)
+{
+  ## Non-temporary table cases
+  # Non transactional table goes first
+  --eval XA START '$xid'
+  --disable_warnings
+  INSERT INTO tm VALUES (1);
+  INSERT INTO t VALUES (1);
+  --enable_warnings
+  --eval XA END '$xid'
+  if ($xa_prepare_opt)
+  {
+   --eval XA PREPARE '$xid'
+  }
+  --eval $xa_terminate '$xid' $one_phase
+
+  # Transactional table goes first
+  --eval XA START '$xid'
+  --disable_warnings
+  INSERT INTO t VALUES (2);
+  INSERT INTO tm VALUES (2);
+  --enable_warnings
+  --eval XA END '$xid'
+  if ($xa_prepare_opt)
+  {
+   --eval XA PREPARE '$xid'
+  }
+  --eval $xa_terminate '$xid' $one_phase
+
+  # The pure non-transactional table
+  --eval XA START '$xid'
+  --disable_warnings
+  INSERT INTO tm VALUES (3);
+  --enable_warnings
+  --eval XA END '$xid'
+  if ($xa_prepare_opt)
+  {
+   --eval XA PREPARE '$xid'
+  }
+  --eval $xa_terminate '$xid' $one_phase
+
+  ## Temporary tables
+  # create outside xa use at the tail
+  CREATE TEMPORARY TABLE tmp_i LIKE t;
+  CREATE TEMPORARY TABLE tmp_m LIKE tm;
+  --eval XA START '$xid'
+  --disable_warnings
+  INSERT INTO t VALUES (4);
+  INSERT INTO tm VALUES (4);
+  INSERT INTO tmp_i VALUES (4);
+  INSERT INTO tmp_m VALUES (4);
+  INSERT INTO t  SELECT * FROM tmp_i;
+  INSERT INTO tm SELECT * FROM tmp_m;
+  --enable_warnings
+  --eval XA END '$xid'
+  if ($xa_prepare_opt)
+  {
+   --eval XA PREPARE '$xid'
+  }
+  --eval $xa_terminate '$xid' $one_phase
+
+  # temporary tables at the head
+  --eval XA START '$xid'
+  --disable_warnings
+  INSERT INTO tmp_i VALUES (5);
+  INSERT INTO tmp_m VALUES (5);
+  INSERT INTO t  SELECT * FROM tmp_i;
+  INSERT INTO tm SELECT * FROM tmp_m;
+  INSERT INTO t VALUES (5);
+  INSERT INTO tm VALUES (5);
+  --enable_warnings
+  --eval XA END '$xid'
+  if ($xa_prepare_opt)
+  {
+   --eval XA PREPARE '$xid'
+  }
+  --eval $xa_terminate '$xid' $one_phase
+
+  # create inside xa use at the tail
+  DROP TEMPORARY TABLE tmp_i;
+  DROP TEMPORARY TABLE tmp_m;
+
+  --eval XA START '$xid'
+  --disable_warnings
+  INSERT INTO t VALUES (6);
+  INSERT INTO tm VALUES (6);
+  CREATE TEMPORARY TABLE tmp_i LIKE t;
+  CREATE TEMPORARY TABLE tmp_m LIKE tm;
+  INSERT INTO tmp_i VALUES (6);
+  INSERT INTO tmp_m VALUES (6);
+  INSERT INTO t  SELECT * FROM tmp_i;
+  INSERT INTO tm SELECT * FROM tmp_m;
+  --enable_warnings
+  --eval XA END '$xid'
+  if ($xa_prepare_opt)
+  {
+   --eval XA PREPARE '$xid'
+  }
+  --eval $xa_terminate '$xid' $one_phase
+
+  # use at the head
+  DROP TEMPORARY TABLE tmp_i;
+  DROP TEMPORARY TABLE tmp_m;
+  --eval XA START '$xid'
+  --disable_warnings
+  CREATE TEMPORARY TABLE tmp_i LIKE t;
+  CREATE TEMPORARY TABLE tmp_m LIKE tm;
+  INSERT INTO tmp_i VALUES (7);
+  INSERT INTO tmp_m VALUES (7);
+  INSERT INTO t  SELECT * FROM tmp_i;
+  INSERT INTO tm SELECT * FROM tmp_m;
+  INSERT INTO t VALUES (7);
+  INSERT INTO tm VALUES (7);
+  --enable_warnings
+  --eval XA END '$xid'
+  if ($xa_prepare_opt)
+  {
+   --eval XA PREPARE '$xid'
+  }
+  --eval $xa_terminate '$xid' $one_phase
+
+  # use at the tail and drop
+  --eval XA START '$xid'
+  --disable_warnings
+  INSERT INTO t VALUES (8);
+  INSERT INTO tm VALUES (8);
+  INSERT INTO tmp_i VALUES (8);
+  INSERT INTO tmp_m VALUES (8);
+  INSERT INTO t  SELECT * FROM tmp_i;
+  INSERT INTO tm SELECT * FROM tmp_m;
+  DROP TEMPORARY TABLE tmp_i;
+  DROP TEMPORARY TABLE tmp_m;
+  --enable_warnings
+  --eval XA END '$xid'
+  if ($xa_prepare_opt)
+  {
+   --eval XA PREPARE '$xid'
+  }
+  --eval $xa_terminate '$xid' $one_phase
+
+  ## Ineffective transactional table operation case
+
+  --eval XA START '$xid'
+  UPDATE t SET a = 99 where a = -1;
+  --eval XA END '$xid'
+  if ($xa_prepare_opt)
+  {
+   --eval XA PREPARE '$xid'
+  }
+  --eval $xa_terminate '$xid' $one_phase
+}
+
+if ($command == cleanup)
+{
+  DROP TABLE t, tm;
+}
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_optimistic_xa.result b/mysql-test/suite/rpl/r/rpl_parallel_optimistic_xa.result
new file mode 100644
index 00000000000..4136f1885db
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_optimistic_xa.result
@@ -0,0 +1,51 @@
+include/master-slave.inc
+[connection master]
+call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction");
+call mtr.add_suppression("WSREP: handlerton rollback failed");
+CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
+connection master;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+connection slave;
+include/stop_slave.inc
+SET @old_parallel_threads            = @@GLOBAL.slave_parallel_threads;
+SET @@global.slave_parallel_threads  = 7;
+SET @old_parallel_mode               = @@GLOBAL.slave_parallel_mode;
+SET @@global.slave_parallel_mode     ='optimistic';
+SET @old_gtid_cleanup_batch_size     = @@GLOBAL.gtid_cleanup_batch_size;
+SET @@global.gtid_cleanup_batch_size = 1000000;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+connection master;
+CREATE TABLE t0 (a int,             b INT) ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 0);
+include/save_master_gtid.inc
+connection slave;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+include/stop_slave.inc
+connection master;
+include/save_master_gtid.inc
+connection slave;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+include/diff_tables.inc [master:t0, slave:t0]
+include/diff_tables.inc [master:t1, slave:t1]
+connection slave;
+include/stop_slave.inc
+set global log_warnings=default;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection master;
+DROP VIEW v_processlist;
+DROP TABLE t0, t1;
+include/save_master_gtid.inc
+connection slave;
+include/sync_with_master_gtid.inc
+SELECT COUNT(*) <= 5*@@GLOBAL.gtid_cleanup_batch_size
+FROM mysql.gtid_slave_pos;
+COUNT(*) <= 5*@@GLOBAL.gtid_cleanup_batch_size
+1
+SET GLOBAL gtid_cleanup_batch_size= @old_gtid_cleanup_batch_size;
+connection master;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_optimistic_xa_lsu_off.result b/mysql-test/suite/rpl/r/rpl_parallel_optimistic_xa_lsu_off.result
new file mode 100644
index 00000000000..4136f1885db
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_optimistic_xa_lsu_off.result
@@ -0,0 +1,51 @@
+include/master-slave.inc
+[connection master]
+call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction");
+call mtr.add_suppression("WSREP: handlerton rollback failed");
+CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
+connection master;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+connection slave;
+include/stop_slave.inc
+SET @old_parallel_threads            = @@GLOBAL.slave_parallel_threads;
+SET @@global.slave_parallel_threads  = 7;
+SET @old_parallel_mode               = @@GLOBAL.slave_parallel_mode;
+SET @@global.slave_parallel_mode     ='optimistic';
+SET @old_gtid_cleanup_batch_size     = @@GLOBAL.gtid_cleanup_batch_size;
+SET @@global.gtid_cleanup_batch_size = 1000000;
+CHANGE MASTER TO master_use_gtid=slave_pos;
+connection master;
+CREATE TABLE t0 (a int,             b INT) ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 0);
+include/save_master_gtid.inc
+connection slave;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+include/stop_slave.inc
+connection master;
+include/save_master_gtid.inc
+connection slave;
+include/start_slave.inc
+include/sync_with_master_gtid.inc
+include/diff_tables.inc [master:t0, slave:t0]
+include/diff_tables.inc [master:t1, slave:t1]
+connection slave;
+include/stop_slave.inc
+set global log_warnings=default;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+include/start_slave.inc
+connection master;
+DROP VIEW v_processlist;
+DROP TABLE t0, t1;
+include/save_master_gtid.inc
+connection slave;
+include/sync_with_master_gtid.inc
+SELECT COUNT(*) <= 5*@@GLOBAL.gtid_cleanup_batch_size
+FROM mysql.gtid_slave_pos;
+COUNT(*) <= 5*@@GLOBAL.gtid_cleanup_batch_size
+1
+SET GLOBAL gtid_cleanup_batch_size= @old_gtid_cleanup_batch_size;
+connection master;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_parallel_xa_same_xid.result b/mysql-test/suite/rpl/r/rpl_parallel_xa_same_xid.result
new file mode 100644
index 00000000000..03fe5157623
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_parallel_xa_same_xid.result
@@ -0,0 +1,23 @@
+include/master-slave.inc
+[connection master]
+connection slave;
+call mtr.add_suppression("WSREP: handlerton rollback failed");
+include/stop_slave.inc
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+SET @old_parallel_threads = @@GLOBAL.slave_parallel_threads;
+SET @old_parallel_mode               = @@GLOBAL.slave_parallel_mode;
+SET @@global.slave_parallel_mode     ='optimistic';
+include/start_slave.inc
+connection master;
+CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY, b INT) ENGINE=InnoDB;
+include/sync_slave_sql_with_master.inc
+include/diff_tables.inc [master:t1, slave:t1]
+connection slave;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+include/start_slave.inc
+connection master;
+DROP TABLE t1, t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_temporary_errors.result b/mysql-test/suite/rpl/r/rpl_temporary_errors.result
index 8654fe218dc..c126871e460 100644
--- a/mysql-test/suite/rpl/r/rpl_temporary_errors.result
+++ b/mysql-test/suite/rpl/r/rpl_temporary_errors.result
@@ -3,7 +3,7 @@ include/master-slave.inc
 call mtr.add_suppression("Deadlock found");
 call mtr.add_suppression("Can't find record in 't.'");
 connection master;
-CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=innodb;
 INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4);
 connection slave;
 SHOW STATUS LIKE 'Slave_retried_transactions';
@@ -11,34 +11,67 @@ Variable_name	Value
 Slave_retried_transactions	0
 set @@global.slave_exec_mode= 'IDEMPOTENT';
 UPDATE t1 SET a = 5, b = 47 WHERE a = 1;
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
 a	b
-5	47
 2	2
 3	3
 4	4
+5	47
 connection master;
 UPDATE t1 SET a = 5, b = 5 WHERE a = 1;
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
 a	b
-5	5
 2	2
 3	3
 4	4
+5	5
 connection slave;
 set @@global.slave_exec_mode= default;
 SHOW STATUS LIKE 'Slave_retried_transactions';
 Variable_name	Value
 Slave_retried_transactions	0
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
 a	b
-5	47
 2	2
 3	3
 4	4
+5	47
 include/check_slave_is_running.inc
 connection slave;
 call mtr.add_suppression("Slave SQL.*Could not execute Update_rows event on table test.t1");
+call mtr.add_suppression("Slave SQL for channel '': worker thread retried transaction");
+call mtr.add_suppression("The slave coordinator and worker threads are stopped");
+connection slave;
+set @save_innodb_lock_wait_timeout=@@global.innodb_lock_wait_timeout;
+set @save_slave_transaction_retries=@@global.slave_transaction_retries;
+set @@global.innodb_lock_wait_timeout=1;
+set @@global.slave_transaction_retries=2;
+include/restart_slave.inc
+connection slave1;
+BEGIN;
+INSERT INTO t1 SET a = 6, b = 7;
+connection master;
+INSERT INTO t1 SET a = 99, b = 99;
+XA START 'xa1';
+INSERT INTO t1 SET a = 6, b = 6;
+XA END 'xa1';
+XA PREPARE 'xa1';
+connection slave;
+include/wait_for_slave_sql_error.inc [errno=1213,1205]
+set @@global.innodb_lock_wait_timeout=1;
+set @@global.slave_transaction_retries=100;
+include/restart_slave.inc
+Warnings:
+Note	1255	Slave already has been stopped
+connection slave1;
+ROLLBACK;
+connection master;
+XA COMMIT 'xa1';
+include/sync_slave_sql_with_master.inc
+connection slave;
+include/assert.inc [XA transaction record must be in the table]
+set @@global.innodb_lock_wait_timeout=@save_innodb_lock_wait_timeout;
+set @@global.slave_transaction_retries= @save_slave_transaction_retries;
 connection master;
 DROP TABLE t1;
 connection slave;
diff --git a/mysql-test/suite/rpl/r/rpl_xa.result b/mysql-test/suite/rpl/r/rpl_xa.result
new file mode 100644
index 00000000000..3420f2348e2
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa.result
@@ -0,0 +1,48 @@
+include/master-slave.inc
+[connection master]
+connection master;
+create table t1 (a int, b int) engine=InnoDB;
+insert into t1 values(0, 0);
+xa start 't';
+insert into t1 values(1, 2);
+xa end 't';
+xa prepare 't';
+xa commit 't';
+connection slave;
+include/diff_tables.inc [master:t1, slave:t1]
+connection master;
+xa start 't';
+insert into t1 values(3, 4);
+xa end 't';
+xa prepare 't';
+xa rollback 't';
+connection slave;
+include/diff_tables.inc [master:t1, slave:t1]
+connection master;
+SET pseudo_slave_mode=1;
+create table t2 (a int) engine=InnoDB;
+xa start 't';
+insert into t1 values (5, 6);
+xa end 't';
+xa prepare 't';
+xa start 's';
+insert into t2 values (0);
+xa end 's';
+xa prepare 's';
+include/save_master_gtid.inc
+connection slave;
+include/sync_with_master_gtid.inc
+xa recover;
+formatID	gtrid_length	bqual_length	data
+1	1	0	t
+1	1	0	s
+connection master;
+xa commit 't';
+xa commit 's';
+SET pseudo_slave_mode=0;
+connection slave;
+include/diff_tables.inc [master:t1, slave:t1]
+include/diff_tables.inc [master:t2, slave:t2]
+connection master;
+drop table t1, t2;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_xa_gap_lock.result b/mysql-test/suite/rpl/r/rpl_xa_gap_lock.result
new file mode 100644
index 00000000000..cb760abe2d2
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa_gap_lock.result
@@ -0,0 +1,44 @@
+include/master-slave.inc
+[connection master]
+connection slave;
+SET @saved_innodb_limit_optimistic_insert_debug = @@GLOBAL.innodb_limit_optimistic_insert_debug;
+SET @@GLOBAL.innodb_limit_optimistic_insert_debug = 2;
+connection master;
+CREATE TABLE t1 (
+c1 INT NOT NULL,
+KEY(c1)
+) ENGINE=InnoDB;
+CREATE TABLE t2 (
+c1 INT NOT NULL,
+FOREIGN KEY(c1) REFERENCES t1(c1)
+) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1), (3), (4);
+connection master1;
+XA START 'XA1';
+INSERT INTO t1 values(2);
+XA END 'XA1';
+connection master;
+XA START 'XA2';
+INSERT INTO t2 values(3);
+XA END 'XA2';
+XA PREPARE 'XA2';
+connection master1;
+XA PREPARE 'XA1';
+XA COMMIT 'XA1';
+connection master;
+XA COMMIT 'XA2';
+include/sync_slave_sql_with_master.inc
+include/stop_slave.inc
+DROP TABLE t2, t1;
+RESET SLAVE;
+RESET MASTER;
+connection master;
+Restore binary log from the master into the slave
+include/diff_tables.inc [master:test.t1, slave:test.t1]
+include/diff_tables.inc [master:test.t2, slave:test.t2]
+DROP TABLE t2, t1;
+connection slave;
+CHANGE MASTER TO MASTER_LOG_FILE='LOG_FILE', MASTER_LOG_POS=LOG_POS;
+SET @@GLOBAL.innodb_limit_optimistic_insert_debug = @saved_innodb_limit_optimistic_insert_debug;
+include/start_slave.inc
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_xa_gtid_pos_auto_engine.result b/mysql-test/suite/rpl/r/rpl_xa_gtid_pos_auto_engine.result
new file mode 100644
index 00000000000..a7ed0f97ea2
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa_gtid_pos_auto_engine.result
@@ -0,0 +1,64 @@
+include/master-slave.inc
+[connection master]
+connection slave;
+call mtr.add_suppression("The automatically created table.*name may not be entirely in lowercase");
+include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=slave_pos;
+SET @@global.gtid_pos_auto_engines="innodb";
+include/start_slave.inc
+connection master;
+create table t1 (a int, b int) engine=InnoDB;
+insert into t1 values(0, 0);
+xa start 't';
+insert into t1 values(1, 2);
+xa end 't';
+xa prepare 't';
+xa commit 't';
+connection slave;
+include/diff_tables.inc [master:t1, slave:t1]
+connection master;
+xa start 't';
+insert into t1 values(3, 4);
+xa end 't';
+xa prepare 't';
+xa rollback 't';
+connection slave;
+include/diff_tables.inc [master:t1, slave:t1]
+connection master;
+SET pseudo_slave_mode=1;
+create table t2 (a int) engine=InnoDB;
+xa start 't';
+insert into t1 values (5, 6);
+xa end 't';
+xa prepare 't';
+xa start 's';
+insert into t2 values (0);
+xa end 's';
+xa prepare 's';
+include/save_master_gtid.inc
+connection slave;
+include/sync_with_master_gtid.inc
+SELECT @@global.gtid_slave_pos = CONCAT(domain_id,"-",server_id,"-",seq_no) FROM mysql.gtid_slave_pos WHERE seq_no = (SELECT DISTINCT max(seq_no) FROM mysql.gtid_slave_pos);
+@@global.gtid_slave_pos = CONCAT(domain_id,"-",server_id,"-",seq_no)
+1
+xa recover;
+formatID	gtrid_length	bqual_length	data
+1	1	0	t
+1	1	0	s
+connection master;
+xa commit 't';
+xa commit 's';
+SET pseudo_slave_mode=0;
+connection slave;
+include/diff_tables.inc [master:t1, slave:t1]
+include/diff_tables.inc [master:t2, slave:t2]
+connection master;
+drop table t1, t2;
+connection slave;
+include/stop_slave.inc
+SET @@global.gtid_pos_auto_engines="";
+SET @@session.sql_log_bin=0;
+DROP TABLE mysql.gtid_slave_pos_InnoDB;
+SET @@session.sql_log_bin=1;
+include/start_slave.inc
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_xa_survive_disconnect.result b/mysql-test/suite/rpl/r/rpl_xa_survive_disconnect.result
new file mode 100644
index 00000000000..d2ed1e2c235
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa_survive_disconnect.result
@@ -0,0 +1,319 @@
+include/master-slave.inc
+[connection master]
+connection master;
+call mtr.add_suppression("Found 2 prepared XA transactions");
+CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
+CREATE DATABASE d1;
+CREATE DATABASE d2;
+CREATE TABLE d1.t (a INT) ENGINE=innodb;
+CREATE TABLE d2.t (a INT) ENGINE=innodb;
+connect  master_conn1, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@session.binlog_format= statement;
+XA START '1-stmt';
+INSERT INTO d1.t VALUES (1);
+XA END '1-stmt';
+XA PREPARE '1-stmt';
+disconnect master_conn1;
+connection master;
+connect  master_conn2, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@session.binlog_format= row;
+XA START '1-row';
+INSERT INTO d2.t VALUES (1);
+XA END '1-row';
+XA PREPARE '1-row';
+disconnect master_conn2;
+connection master;
+XA START '2';
+INSERT INTO d1.t VALUES (2);
+XA END '2';
+XA PREPARE '2';
+XA COMMIT '2';
+XA COMMIT '1-row';
+XA COMMIT '1-stmt';
+include/show_binlog_events.inc
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Gtid	#	#	BEGIN GTID #-#-#
+master-bin.000001	#	Query	#	#	use `mtr`; INSERT INTO test_suppressions (pattern) VALUES ( NAME_CONST('pattern',_latin1'Found 2 prepared XA transactions' COLLATE 'latin1_swedish_ci'))
+master-bin.000001	#	Query	#	#	COMMIT
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_processlist` AS SELECT * FROM performance_schema.threads where type = 'FOREGROUND'
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	CREATE DATABASE d1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	CREATE DATABASE d2
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; CREATE TABLE d1.t (a INT) ENGINE=innodb
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; CREATE TABLE d2.t (a INT) ENGINE=innodb
+master-bin.000001	#	Gtid	#	#	XA START X'312d73746d74',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO d1.t VALUES (1)
+master-bin.000001	#	Query	#	#	XA END X'312d73746d74',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'312d73746d74',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'312d726f77',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO d2.t VALUES (1)
+master-bin.000001	#	Table_map	#	#	table_id: # (d2.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'312d726f77',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'312d726f77',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'32',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO d1.t VALUES (2)
+master-bin.000001	#	Query	#	#	XA END X'32',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'32',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'32',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'312d726f77',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'312d73746d74',X'',1
+include/sync_slave_sql_with_master.inc
+include/stop_slave.inc
+connection master;
+connect  master2, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master2;
+SET @@session.binlog_format= statement;
+XA START '3-stmt';
+INSERT INTO d1.t VALUES (3);
+XA END '3-stmt';
+XA PREPARE '3-stmt';
+disconnect master2;
+connect  master2, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master2;
+SET @@session.binlog_format= row;
+XA START '3-row';
+INSERT INTO d2.t VALUES (4);
+XA END '3-row';
+XA PREPARE '3-row';
+disconnect master2;
+connection master;
+connect  master2, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master2;
+XA START '4';
+SELECT * FROM d1.t;
+a
+1
+2
+XA END '4';
+XA PREPARE '4';
+disconnect master2;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_10';
+INSERT INTO d1.t VALUES (10);
+INSERT INTO d2.t VALUES (10);
+XA END 'bulk_trx_10';
+XA PREPARE 'bulk_trx_10';
+disconnect master_bulk_conn10;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_9';
+INSERT INTO d1.t VALUES (9);
+INSERT INTO d2.t VALUES (9);
+XA END 'bulk_trx_9';
+XA PREPARE 'bulk_trx_9';
+disconnect master_bulk_conn9;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_8';
+INSERT INTO d1.t VALUES (8);
+INSERT INTO d2.t VALUES (8);
+XA END 'bulk_trx_8';
+XA PREPARE 'bulk_trx_8';
+disconnect master_bulk_conn8;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_7';
+INSERT INTO d1.t VALUES (7);
+INSERT INTO d2.t VALUES (7);
+XA END 'bulk_trx_7';
+XA PREPARE 'bulk_trx_7';
+disconnect master_bulk_conn7;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_6';
+INSERT INTO d1.t VALUES (6);
+INSERT INTO d2.t VALUES (6);
+XA END 'bulk_trx_6';
+XA PREPARE 'bulk_trx_6';
+disconnect master_bulk_conn6;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_5';
+INSERT INTO d1.t VALUES (5);
+INSERT INTO d2.t VALUES (5);
+XA END 'bulk_trx_5';
+XA PREPARE 'bulk_trx_5';
+disconnect master_bulk_conn5;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_4';
+INSERT INTO d1.t VALUES (4);
+INSERT INTO d2.t VALUES (4);
+XA END 'bulk_trx_4';
+XA PREPARE 'bulk_trx_4';
+disconnect master_bulk_conn4;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_3';
+INSERT INTO d1.t VALUES (3);
+INSERT INTO d2.t VALUES (3);
+XA END 'bulk_trx_3';
+XA PREPARE 'bulk_trx_3';
+disconnect master_bulk_conn3;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_2';
+INSERT INTO d1.t VALUES (2);
+INSERT INTO d2.t VALUES (2);
+XA END 'bulk_trx_2';
+XA PREPARE 'bulk_trx_2';
+disconnect master_bulk_conn2;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_1';
+INSERT INTO d1.t VALUES (1);
+INSERT INTO d2.t VALUES (1);
+XA END 'bulk_trx_1';
+XA PREPARE 'bulk_trx_1';
+disconnect master_bulk_conn1;
+connection master;
+connection slave;
+include/start_slave.inc
+connection master;
+include/sync_slave_sql_with_master.inc
+include/stop_slave.inc
+connection master;
+XA COMMIT 'bulk_trx_10';
+XA ROLLBACK 'bulk_trx_9';
+XA COMMIT 'bulk_trx_8';
+XA ROLLBACK 'bulk_trx_7';
+XA COMMIT 'bulk_trx_6';
+XA ROLLBACK 'bulk_trx_5';
+XA COMMIT 'bulk_trx_4';
+XA ROLLBACK 'bulk_trx_3';
+XA COMMIT 'bulk_trx_2';
+XA ROLLBACK 'bulk_trx_1';
+include/rpl_restart_server.inc [server_number=1]
+connection slave;
+include/start_slave.inc
+connection master;
+*** '3-stmt','3-row' xa-transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	6	0	3-stmt
+1	5	0	3-row
+XA COMMIT '3-stmt';
+XA ROLLBACK '3-row';
+include/sync_slave_sql_with_master.inc
+connection master;
+connect  master_conn2, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START '0123456789012345678901234567890123456789012345678901234567890124','0123456789012345678901234567890123456789012345678901234567890124',4294967292;
+INSERT INTO d1.t VALUES (64);
+XA END '0123456789012345678901234567890123456789012345678901234567890124','0123456789012345678901234567890123456789012345678901234567890124',4294967292;
+XA PREPARE '0123456789012345678901234567890123456789012345678901234567890124','0123456789012345678901234567890123456789012345678901234567890124',4294967292;
+disconnect master_conn2;
+connection master;
+connect  master_conn3, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',X'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',0;
+INSERT INTO d1.t VALUES (0);
+XA END X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',X'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',0;
+XA PREPARE X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',X'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',0;
+disconnect master_conn3;
+connection master;
+disconnect master_conn4;
+connection master;
+XA COMMIT '0123456789012345678901234567890123456789012345678901234567890124','0123456789012345678901234567890123456789012345678901234567890124',4294967292;
+XA COMMIT X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',X'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',0;
+XA COMMIT 'RANDOM XID'
+include/sync_slave_sql_with_master.inc
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn10;
+XA START 'one_phase_10';
+INSERT INTO d1.t VALUES (10);
+INSERT INTO d2.t VALUES (10);
+XA END 'one_phase_10';
+XA COMMIT 'one_phase_10' ONE PHASE;
+disconnect master_bulk_conn10;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn9;
+XA START 'one_phase_9';
+INSERT INTO d1.t VALUES (9);
+INSERT INTO d2.t VALUES (9);
+XA END 'one_phase_9';
+XA COMMIT 'one_phase_9' ONE PHASE;
+disconnect master_bulk_conn9;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn8;
+XA START 'one_phase_8';
+INSERT INTO d1.t VALUES (8);
+INSERT INTO d2.t VALUES (8);
+XA END 'one_phase_8';
+XA COMMIT 'one_phase_8' ONE PHASE;
+disconnect master_bulk_conn8;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn7;
+XA START 'one_phase_7';
+INSERT INTO d1.t VALUES (7);
+INSERT INTO d2.t VALUES (7);
+XA END 'one_phase_7';
+XA COMMIT 'one_phase_7' ONE PHASE;
+disconnect master_bulk_conn7;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn6;
+XA START 'one_phase_6';
+INSERT INTO d1.t VALUES (6);
+INSERT INTO d2.t VALUES (6);
+XA END 'one_phase_6';
+XA COMMIT 'one_phase_6' ONE PHASE;
+disconnect master_bulk_conn6;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn5;
+XA START 'one_phase_5';
+INSERT INTO d1.t VALUES (5);
+INSERT INTO d2.t VALUES (5);
+XA END 'one_phase_5';
+XA COMMIT 'one_phase_5' ONE PHASE;
+disconnect master_bulk_conn5;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn4;
+XA START 'one_phase_4';
+INSERT INTO d1.t VALUES (4);
+INSERT INTO d2.t VALUES (4);
+XA END 'one_phase_4';
+XA COMMIT 'one_phase_4' ONE PHASE;
+disconnect master_bulk_conn4;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn3;
+XA START 'one_phase_3';
+INSERT INTO d1.t VALUES (3);
+INSERT INTO d2.t VALUES (3);
+XA END 'one_phase_3';
+XA COMMIT 'one_phase_3' ONE PHASE;
+disconnect master_bulk_conn3;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn2;
+XA START 'one_phase_2';
+INSERT INTO d1.t VALUES (2);
+INSERT INTO d2.t VALUES (2);
+XA END 'one_phase_2';
+XA COMMIT 'one_phase_2' ONE PHASE;
+disconnect master_bulk_conn2;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn1;
+XA START 'one_phase_1';
+INSERT INTO d1.t VALUES (1);
+INSERT INTO d2.t VALUES (1);
+XA END 'one_phase_1';
+XA COMMIT 'one_phase_1' ONE PHASE;
+disconnect master_bulk_conn1;
+connection master;
+include/sync_slave_sql_with_master.inc
+include/diff_tables.inc [master:d1.t, slave:d1.t]
+include/diff_tables.inc [master:d2.t, slave:d2.t]
+connection master;
+DELETE FROM d1.t;
+DELETE FROM d2.t;
+DROP TABLE d1.t, d2.t;
+DROP DATABASE d1;
+DROP DATABASE d2;
+DROP VIEW v_processlist;
+include/sync_slave_sql_with_master.inc
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_xa_survive_disconnect_lsu_off.result b/mysql-test/suite/rpl/r/rpl_xa_survive_disconnect_lsu_off.result
new file mode 100644
index 00000000000..d2ed1e2c235
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa_survive_disconnect_lsu_off.result
@@ -0,0 +1,319 @@
+include/master-slave.inc
+[connection master]
+connection master;
+call mtr.add_suppression("Found 2 prepared XA transactions");
+CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
+CREATE DATABASE d1;
+CREATE DATABASE d2;
+CREATE TABLE d1.t (a INT) ENGINE=innodb;
+CREATE TABLE d2.t (a INT) ENGINE=innodb;
+connect  master_conn1, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@session.binlog_format= statement;
+XA START '1-stmt';
+INSERT INTO d1.t VALUES (1);
+XA END '1-stmt';
+XA PREPARE '1-stmt';
+disconnect master_conn1;
+connection master;
+connect  master_conn2, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+SET @@session.binlog_format= row;
+XA START '1-row';
+INSERT INTO d2.t VALUES (1);
+XA END '1-row';
+XA PREPARE '1-row';
+disconnect master_conn2;
+connection master;
+XA START '2';
+INSERT INTO d1.t VALUES (2);
+XA END '2';
+XA PREPARE '2';
+XA COMMIT '2';
+XA COMMIT '1-row';
+XA COMMIT '1-stmt';
+include/show_binlog_events.inc
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Gtid	#	#	BEGIN GTID #-#-#
+master-bin.000001	#	Query	#	#	use `mtr`; INSERT INTO test_suppressions (pattern) VALUES ( NAME_CONST('pattern',_latin1'Found 2 prepared XA transactions' COLLATE 'latin1_swedish_ci'))
+master-bin.000001	#	Query	#	#	COMMIT
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_processlist` AS SELECT * FROM performance_schema.threads where type = 'FOREGROUND'
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	CREATE DATABASE d1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	CREATE DATABASE d2
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; CREATE TABLE d1.t (a INT) ENGINE=innodb
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; CREATE TABLE d2.t (a INT) ENGINE=innodb
+master-bin.000001	#	Gtid	#	#	XA START X'312d73746d74',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO d1.t VALUES (1)
+master-bin.000001	#	Query	#	#	XA END X'312d73746d74',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'312d73746d74',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'312d726f77',X'',1 GTID #-#-#
+master-bin.000001	#	Annotate_rows	#	#	INSERT INTO d2.t VALUES (1)
+master-bin.000001	#	Table_map	#	#	table_id: # (d2.t)
+master-bin.000001	#	Write_rows_v1	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	XA END X'312d726f77',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'312d726f77',X'',1
+master-bin.000001	#	Gtid	#	#	XA START X'32',X'',1 GTID #-#-#
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO d1.t VALUES (2)
+master-bin.000001	#	Query	#	#	XA END X'32',X'',1
+master-bin.000001	#	XA_prepare	#	#	XA PREPARE X'32',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'32',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'312d726f77',X'',1
+master-bin.000001	#	Gtid	#	#	GTID #-#-#
+master-bin.000001	#	Query	#	#	XA COMMIT X'312d73746d74',X'',1
+include/sync_slave_sql_with_master.inc
+include/stop_slave.inc
+connection master;
+connect  master2, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master2;
+SET @@session.binlog_format= statement;
+XA START '3-stmt';
+INSERT INTO d1.t VALUES (3);
+XA END '3-stmt';
+XA PREPARE '3-stmt';
+disconnect master2;
+connect  master2, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master2;
+SET @@session.binlog_format= row;
+XA START '3-row';
+INSERT INTO d2.t VALUES (4);
+XA END '3-row';
+XA PREPARE '3-row';
+disconnect master2;
+connection master;
+connect  master2, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master2;
+XA START '4';
+SELECT * FROM d1.t;
+a
+1
+2
+XA END '4';
+XA PREPARE '4';
+disconnect master2;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_10';
+INSERT INTO d1.t VALUES (10);
+INSERT INTO d2.t VALUES (10);
+XA END 'bulk_trx_10';
+XA PREPARE 'bulk_trx_10';
+disconnect master_bulk_conn10;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_9';
+INSERT INTO d1.t VALUES (9);
+INSERT INTO d2.t VALUES (9);
+XA END 'bulk_trx_9';
+XA PREPARE 'bulk_trx_9';
+disconnect master_bulk_conn9;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_8';
+INSERT INTO d1.t VALUES (8);
+INSERT INTO d2.t VALUES (8);
+XA END 'bulk_trx_8';
+XA PREPARE 'bulk_trx_8';
+disconnect master_bulk_conn8;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_7';
+INSERT INTO d1.t VALUES (7);
+INSERT INTO d2.t VALUES (7);
+XA END 'bulk_trx_7';
+XA PREPARE 'bulk_trx_7';
+disconnect master_bulk_conn7;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_6';
+INSERT INTO d1.t VALUES (6);
+INSERT INTO d2.t VALUES (6);
+XA END 'bulk_trx_6';
+XA PREPARE 'bulk_trx_6';
+disconnect master_bulk_conn6;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_5';
+INSERT INTO d1.t VALUES (5);
+INSERT INTO d2.t VALUES (5);
+XA END 'bulk_trx_5';
+XA PREPARE 'bulk_trx_5';
+disconnect master_bulk_conn5;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_4';
+INSERT INTO d1.t VALUES (4);
+INSERT INTO d2.t VALUES (4);
+XA END 'bulk_trx_4';
+XA PREPARE 'bulk_trx_4';
+disconnect master_bulk_conn4;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_3';
+INSERT INTO d1.t VALUES (3);
+INSERT INTO d2.t VALUES (3);
+XA END 'bulk_trx_3';
+XA PREPARE 'bulk_trx_3';
+disconnect master_bulk_conn3;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_2';
+INSERT INTO d1.t VALUES (2);
+INSERT INTO d2.t VALUES (2);
+XA END 'bulk_trx_2';
+XA PREPARE 'bulk_trx_2';
+disconnect master_bulk_conn2;
+connection master;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START 'bulk_trx_1';
+INSERT INTO d1.t VALUES (1);
+INSERT INTO d2.t VALUES (1);
+XA END 'bulk_trx_1';
+XA PREPARE 'bulk_trx_1';
+disconnect master_bulk_conn1;
+connection master;
+connection slave;
+include/start_slave.inc
+connection master;
+include/sync_slave_sql_with_master.inc
+include/stop_slave.inc
+connection master;
+XA COMMIT 'bulk_trx_10';
+XA ROLLBACK 'bulk_trx_9';
+XA COMMIT 'bulk_trx_8';
+XA ROLLBACK 'bulk_trx_7';
+XA COMMIT 'bulk_trx_6';
+XA ROLLBACK 'bulk_trx_5';
+XA COMMIT 'bulk_trx_4';
+XA ROLLBACK 'bulk_trx_3';
+XA COMMIT 'bulk_trx_2';
+XA ROLLBACK 'bulk_trx_1';
+include/rpl_restart_server.inc [server_number=1]
+connection slave;
+include/start_slave.inc
+connection master;
+*** '3-stmt','3-row' xa-transactions must be in the list ***
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	6	0	3-stmt
+1	5	0	3-row
+XA COMMIT '3-stmt';
+XA ROLLBACK '3-row';
+include/sync_slave_sql_with_master.inc
+connection master;
+connect  master_conn2, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START '0123456789012345678901234567890123456789012345678901234567890124','0123456789012345678901234567890123456789012345678901234567890124',4294967292;
+INSERT INTO d1.t VALUES (64);
+XA END '0123456789012345678901234567890123456789012345678901234567890124','0123456789012345678901234567890123456789012345678901234567890124',4294967292;
+XA PREPARE '0123456789012345678901234567890123456789012345678901234567890124','0123456789012345678901234567890123456789012345678901234567890124',4294967292;
+disconnect master_conn2;
+connection master;
+connect  master_conn3, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+XA START X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',X'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',0;
+INSERT INTO d1.t VALUES (0);
+XA END X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',X'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',0;
+XA PREPARE X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',X'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',0;
+disconnect master_conn3;
+connection master;
+disconnect master_conn4;
+connection master;
+XA COMMIT '0123456789012345678901234567890123456789012345678901234567890124','0123456789012345678901234567890123456789012345678901234567890124',4294967292;
+XA COMMIT X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',X'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',0;
+XA COMMIT 'RANDOM XID'
+include/sync_slave_sql_with_master.inc
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn10;
+XA START 'one_phase_10';
+INSERT INTO d1.t VALUES (10);
+INSERT INTO d2.t VALUES (10);
+XA END 'one_phase_10';
+XA COMMIT 'one_phase_10' ONE PHASE;
+disconnect master_bulk_conn10;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn9;
+XA START 'one_phase_9';
+INSERT INTO d1.t VALUES (9);
+INSERT INTO d2.t VALUES (9);
+XA END 'one_phase_9';
+XA COMMIT 'one_phase_9' ONE PHASE;
+disconnect master_bulk_conn9;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn8;
+XA START 'one_phase_8';
+INSERT INTO d1.t VALUES (8);
+INSERT INTO d2.t VALUES (8);
+XA END 'one_phase_8';
+XA COMMIT 'one_phase_8' ONE PHASE;
+disconnect master_bulk_conn8;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn7;
+XA START 'one_phase_7';
+INSERT INTO d1.t VALUES (7);
+INSERT INTO d2.t VALUES (7);
+XA END 'one_phase_7';
+XA COMMIT 'one_phase_7' ONE PHASE;
+disconnect master_bulk_conn7;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn6;
+XA START 'one_phase_6';
+INSERT INTO d1.t VALUES (6);
+INSERT INTO d2.t VALUES (6);
+XA END 'one_phase_6';
+XA COMMIT 'one_phase_6' ONE PHASE;
+disconnect master_bulk_conn6;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn5;
+XA START 'one_phase_5';
+INSERT INTO d1.t VALUES (5);
+INSERT INTO d2.t VALUES (5);
+XA END 'one_phase_5';
+XA COMMIT 'one_phase_5' ONE PHASE;
+disconnect master_bulk_conn5;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn4;
+XA START 'one_phase_4';
+INSERT INTO d1.t VALUES (4);
+INSERT INTO d2.t VALUES (4);
+XA END 'one_phase_4';
+XA COMMIT 'one_phase_4' ONE PHASE;
+disconnect master_bulk_conn4;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn3;
+XA START 'one_phase_3';
+INSERT INTO d1.t VALUES (3);
+INSERT INTO d2.t VALUES (3);
+XA END 'one_phase_3';
+XA COMMIT 'one_phase_3' ONE PHASE;
+disconnect master_bulk_conn3;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn2;
+XA START 'one_phase_2';
+INSERT INTO d1.t VALUES (2);
+INSERT INTO d2.t VALUES (2);
+XA END 'one_phase_2';
+XA COMMIT 'one_phase_2' ONE PHASE;
+disconnect master_bulk_conn2;
+connect  master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection master_bulk_conn1;
+XA START 'one_phase_1';
+INSERT INTO d1.t VALUES (1);
+INSERT INTO d2.t VALUES (1);
+XA END 'one_phase_1';
+XA COMMIT 'one_phase_1' ONE PHASE;
+disconnect master_bulk_conn1;
+connection master;
+include/sync_slave_sql_with_master.inc
+include/diff_tables.inc [master:d1.t, slave:d1.t]
+include/diff_tables.inc [master:d2.t, slave:d2.t]
+connection master;
+DELETE FROM d1.t;
+DELETE FROM d2.t;
+DROP TABLE d1.t, d2.t;
+DROP DATABASE d1;
+DROP DATABASE d2;
+DROP VIEW v_processlist;
+include/sync_slave_sql_with_master.inc
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_xa_survive_disconnect_mixed_engines.result b/mysql-test/suite/rpl/r/rpl_xa_survive_disconnect_mixed_engines.result
new file mode 100644
index 00000000000..09bfffc0da4
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa_survive_disconnect_mixed_engines.result
@@ -0,0 +1,373 @@
+include/master-slave.inc
+[connection master]
+connection master;
+CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
+SET @@session.binlog_direct_non_transactional_updates := if(floor(rand()*10)%2,'ON','OFF');
+CREATE TABLE t (a INT) ENGINE=innodb;
+CREATE TABLE tm (a INT) ENGINE=myisam;
+=== COMMIT ===
+XA START 'xa_trx';
+INSERT INTO tm VALUES (1);
+INSERT INTO t VALUES (1);
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+XA COMMIT 'xa_trx' ;
+XA START 'xa_trx';
+INSERT INTO t VALUES (2);
+INSERT INTO tm VALUES (2);
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+XA COMMIT 'xa_trx' ;
+XA START 'xa_trx';
+INSERT INTO tm VALUES (3);
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+XA COMMIT 'xa_trx' ;
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+XA START 'xa_trx';
+INSERT INTO t VALUES (4);
+INSERT INTO tm VALUES (4);
+INSERT INTO tmp_i VALUES (4);
+INSERT INTO tmp_m VALUES (4);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+XA COMMIT 'xa_trx' ;
+XA START 'xa_trx';
+INSERT INTO tmp_i VALUES (5);
+INSERT INTO tmp_m VALUES (5);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+INSERT INTO t VALUES (5);
+INSERT INTO tm VALUES (5);
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+XA COMMIT 'xa_trx' ;
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA START 'xa_trx';
+INSERT INTO t VALUES (6);
+INSERT INTO tm VALUES (6);
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+INSERT INTO tmp_i VALUES (6);
+INSERT INTO tmp_m VALUES (6);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+XA COMMIT 'xa_trx' ;
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA START 'xa_trx';
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+INSERT INTO tmp_i VALUES (7);
+INSERT INTO tmp_m VALUES (7);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+INSERT INTO t VALUES (7);
+INSERT INTO tm VALUES (7);
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+XA COMMIT 'xa_trx' ;
+XA START 'xa_trx';
+INSERT INTO t VALUES (8);
+INSERT INTO tm VALUES (8);
+INSERT INTO tmp_i VALUES (8);
+INSERT INTO tmp_m VALUES (8);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+XA COMMIT 'xa_trx' ;
+XA START 'xa_trx';
+UPDATE t SET a = 99 where a = -1;
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+XA COMMIT 'xa_trx' ;
+include/sync_slave_sql_with_master.inc
+connection master;
+=== COMMIT ONE PHASE ===
+XA START 'xa_trx';
+INSERT INTO tm VALUES (1);
+INSERT INTO t VALUES (1);
+XA END 'xa_trx';
+XA COMMIT 'xa_trx' ONE PHASE;
+XA START 'xa_trx';
+INSERT INTO t VALUES (2);
+INSERT INTO tm VALUES (2);
+XA END 'xa_trx';
+XA COMMIT 'xa_trx' ONE PHASE;
+XA START 'xa_trx';
+INSERT INTO tm VALUES (3);
+XA END 'xa_trx';
+XA COMMIT 'xa_trx' ONE PHASE;
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+XA START 'xa_trx';
+INSERT INTO t VALUES (4);
+INSERT INTO tm VALUES (4);
+INSERT INTO tmp_i VALUES (4);
+INSERT INTO tmp_m VALUES (4);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+XA END 'xa_trx';
+XA COMMIT 'xa_trx' ONE PHASE;
+XA START 'xa_trx';
+INSERT INTO tmp_i VALUES (5);
+INSERT INTO tmp_m VALUES (5);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+INSERT INTO t VALUES (5);
+INSERT INTO tm VALUES (5);
+XA END 'xa_trx';
+XA COMMIT 'xa_trx' ONE PHASE;
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA START 'xa_trx';
+INSERT INTO t VALUES (6);
+INSERT INTO tm VALUES (6);
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+INSERT INTO tmp_i VALUES (6);
+INSERT INTO tmp_m VALUES (6);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+XA END 'xa_trx';
+XA COMMIT 'xa_trx' ONE PHASE;
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA START 'xa_trx';
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+INSERT INTO tmp_i VALUES (7);
+INSERT INTO tmp_m VALUES (7);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+INSERT INTO t VALUES (7);
+INSERT INTO tm VALUES (7);
+XA END 'xa_trx';
+XA COMMIT 'xa_trx' ONE PHASE;
+XA START 'xa_trx';
+INSERT INTO t VALUES (8);
+INSERT INTO tm VALUES (8);
+INSERT INTO tmp_i VALUES (8);
+INSERT INTO tmp_m VALUES (8);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA END 'xa_trx';
+XA COMMIT 'xa_trx' ONE PHASE;
+XA START 'xa_trx';
+UPDATE t SET a = 99 where a = -1;
+XA END 'xa_trx';
+XA COMMIT 'xa_trx' ONE PHASE;
+include/sync_slave_sql_with_master.inc
+connection master;
+=== ROLLBACK with PREPARE ===
+XA START 'xa_trx';
+INSERT INTO tm VALUES (1);
+INSERT INTO t VALUES (1);
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+XA START 'xa_trx';
+INSERT INTO t VALUES (2);
+INSERT INTO tm VALUES (2);
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+XA START 'xa_trx';
+INSERT INTO tm VALUES (3);
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+XA START 'xa_trx';
+INSERT INTO t VALUES (4);
+INSERT INTO tm VALUES (4);
+INSERT INTO tmp_i VALUES (4);
+INSERT INTO tmp_m VALUES (4);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+XA START 'xa_trx';
+INSERT INTO tmp_i VALUES (5);
+INSERT INTO tmp_m VALUES (5);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+INSERT INTO t VALUES (5);
+INSERT INTO tm VALUES (5);
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA START 'xa_trx';
+INSERT INTO t VALUES (6);
+INSERT INTO tm VALUES (6);
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+INSERT INTO tmp_i VALUES (6);
+INSERT INTO tmp_m VALUES (6);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA START 'xa_trx';
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+INSERT INTO tmp_i VALUES (7);
+INSERT INTO tmp_m VALUES (7);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+INSERT INTO t VALUES (7);
+INSERT INTO tm VALUES (7);
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+XA START 'xa_trx';
+INSERT INTO t VALUES (8);
+INSERT INTO tm VALUES (8);
+INSERT INTO tmp_i VALUES (8);
+INSERT INTO tmp_m VALUES (8);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+XA START 'xa_trx';
+UPDATE t SET a = 99 where a = -1;
+XA END 'xa_trx';
+XA PREPARE 'xa_trx';
+xa rollback 'xa_trx' ;
+include/sync_slave_sql_with_master.inc
+connection master;
+=== ROLLBACK with no PREPARE ===
+XA START 'xa_trx';
+INSERT INTO tm VALUES (1);
+INSERT INTO t VALUES (1);
+XA END 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+XA START 'xa_trx';
+INSERT INTO t VALUES (2);
+INSERT INTO tm VALUES (2);
+XA END 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+XA START 'xa_trx';
+INSERT INTO tm VALUES (3);
+XA END 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+XA START 'xa_trx';
+INSERT INTO t VALUES (4);
+INSERT INTO tm VALUES (4);
+INSERT INTO tmp_i VALUES (4);
+INSERT INTO tmp_m VALUES (4);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+XA END 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+XA START 'xa_trx';
+INSERT INTO tmp_i VALUES (5);
+INSERT INTO tmp_m VALUES (5);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+INSERT INTO t VALUES (5);
+INSERT INTO tm VALUES (5);
+XA END 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA START 'xa_trx';
+INSERT INTO t VALUES (6);
+INSERT INTO tm VALUES (6);
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+INSERT INTO tmp_i VALUES (6);
+INSERT INTO tmp_m VALUES (6);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+XA END 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA START 'xa_trx';
+CREATE TEMPORARY TABLE tmp_i LIKE t;
+CREATE TEMPORARY TABLE tmp_m LIKE tm;
+INSERT INTO tmp_i VALUES (7);
+INSERT INTO tmp_m VALUES (7);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+INSERT INTO t VALUES (7);
+INSERT INTO tm VALUES (7);
+XA END 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+XA START 'xa_trx';
+INSERT INTO t VALUES (8);
+INSERT INTO tm VALUES (8);
+INSERT INTO tmp_i VALUES (8);
+INSERT INTO tmp_m VALUES (8);
+INSERT INTO t  SELECT * FROM tmp_i;
+INSERT INTO tm SELECT * FROM tmp_m;
+DROP TEMPORARY TABLE tmp_i;
+DROP TEMPORARY TABLE tmp_m;
+XA END 'xa_trx';
+xa rollback 'xa_trx' ;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+XA START 'xa_trx';
+UPDATE t SET a = 99 where a = -1;
+XA END 'xa_trx';
+xa rollback 'xa_trx' ;
+include/sync_slave_sql_with_master.inc
+include/diff_tables.inc [master:tm, slave:tm]
+connection master;
+DROP TABLE t, tm;
+include/sync_slave_sql_with_master.inc
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa.test b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa.test
new file mode 100644
index 00000000000..35c22d1e92e
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa.test
@@ -0,0 +1,235 @@
+# The tests verify concurrent execution of replicated (MDEV-742)
+# XA transactions in the parallel optimistic mode.
+
+--source include/have_innodb.inc
+--source include/have_perfschema.inc
+--source include/master-slave.inc
+
+# Tests' global declarations
+--let $trx = _trx_
+
+call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction");
+call mtr.add_suppression("WSREP: handlerton rollback failed");
+#call mtr.add_suppression("Can't find record in 't1'");
+CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
+
+--connection master
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+--save_master_pos
+
+# Prepare to restart slave into optimistic parallel mode
+--connection slave
+--sync_with_master
+--source include/stop_slave.inc
+SET @old_parallel_threads            = @@GLOBAL.slave_parallel_threads;
+SET @@global.slave_parallel_threads  = 7;
+SET @old_parallel_mode               = @@GLOBAL.slave_parallel_mode;
+SET @@global.slave_parallel_mode     ='optimistic';
+# Run the first part of the test with high batch size and see that
+# old rows remain in the table.
+SET @old_gtid_cleanup_batch_size     = @@GLOBAL.gtid_cleanup_batch_size;
+SET @@global.gtid_cleanup_batch_size = 1000000;
+
+CHANGE MASTER TO master_use_gtid=slave_pos;
+
+# LOAD GENERATOR creates XA:s interleaved in binlog when they are from
+# different connections. All the following block XA:s of the same connection
+# update the same data which challenges slave optimistic scheduler's correctness.
+# Slave must eventually apply such load, and correctly (checked).
+
+--connection master
+CREATE TABLE t0 (a int,             b INT) ENGINE=InnoDB;
+CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 0);
+
+
+# I. Logging some sequence of XA:s by one connection.
+#
+# The slave applier's task is to successfully execute a series of
+# Prepare and Complete parts of a sequence of XA:s
+
+--let $trx_num = 300
+--let $i       = $trx_num
+--let $conn    = master
+--disable_query_log
+while($i > 0)
+{
+  # 'decision' to commit 0, or rollback 1
+  --let  $decision = `SELECT $i % 2`
+  --eval XA START '$conn$trx$i'
+  --eval   UPDATE t1 SET b = 1 - 2 * $decision WHERE a = 1
+  --eval XA END '$conn$trx$i'
+  --let $one_phase = `SELECT IF(floor(rand()*10)%2, "ONE PHASE", 0)`
+  if (!$one_phase)
+  {
+    --eval XA PREPARE '$conn$trx$i'
+    --let $one_phase =
+  }
+
+  --let $term = COMMIT
+  if ($decision)
+  {
+    --let $term = ROLLBACK
+    --let $one_phase =
+  }
+  --eval XA $term '$conn$trx$i' $one_phase
+
+  --dec $i
+}
+--enable_query_log
+--source include/save_master_gtid.inc
+
+--connection slave
+--source include/start_slave.inc
+--source include/sync_with_master_gtid.inc
+--source include/stop_slave.inc
+
+
+# II. Logging XS:s from multiple connections in random interweaving manner:
+#
+# in a loop ($i) per connection
+#   arrange an inner ($k) loop where
+#     start and prepare an XA;
+#     decide whether to terminate it and then continue to loop innerly
+#     OR disconnect to break the inner loop;
+#   the disconnected one's XA is taken care by 'master' connection
+#
+# Effectively binlog must collect a well mixed XA- prepared and terminated
+# groups for slave to handle.
+
+--connection master
+# Total # of connections
+--let $conn_num=53
+
+--let $i = $conn_num
+--disable_query_log
+while($i > 0)
+{
+  --connect (master_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,)
+--dec $i
+}
+--enable_query_log
+
+--let $i = $conn_num
+while($i > 0)
+{
+  --let $conn_i      = conn$i
+  # $i2 indexes the current connection's "own" row
+  --let $i2 = `SELECT $i + 2`
+--disable_query_log
+  --connection master_conn$i
+--enable_query_log
+  --disable_query_log
+  --let $i_conn_id   = `SELECT connection_id()`
+
+  --let $decision  = 0
+  # the row id of the last connection that committed its XA
+  --let $c_max     = 1
+  --let $k         = 0
+  while ($decision < 3)
+  {
+    --inc $k
+    --eval XA START '$conn_i$trx$k'
+    # UPDATE depends on previously *committed* transactions
+    --eval UPDATE t1 SET b = b + $k + 1 WHERE a = $c_max
+    if (`SELECT $k % 2 = 1`)
+    {
+    --eval REPLACE INTO t1 VALUES ($i2, $k)
+    }
+    if (`SELECT $k % 2 = 0`)
+    {
+    --eval DELETE FROM t1 WHERE a = $i2
+    }
+    CREATE TEMPORARY TABLE tmp LIKE t0;
+    --eval INSERT INTO tmp SET a=$i, b= $k
+    INSERT INTO t0 SELECT * FROM tmp;
+    DROP TEMPORARY TABLE tmp;
+    --eval XA END '$conn_i$trx$k'
+
+    --let $term = COMMIT
+    --let $decision  = `SELECT (floor(rand()*10 % 10) + ($i+$k)) % 4`
+    if ($decision == 1)
+    {
+    --let $term = ROLLBACK
+    }
+    if ($decision < 2)
+    {
+    --eval XA PREPARE '$conn_i$trx$k'
+    --eval XA $term '$conn_i$trx$k'
+    # Iteration counter is taken care *now*
+    }
+    if ($decision == 2)
+    {
+    --eval XA COMMIT '$conn_i$trx$k' ONE PHASE
+    }
+  }
+
+  # $decision = 3
+  --eval XA PREPARE '$conn_i$trx$k'
+  # disconnect now
+  --disconnect master_conn$i
+  --connection master
+
+  --let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $i_conn_id
+  --source include/wait_condition.inc
+
+  --disable_query_log
+  --let $decision = `SELECT ($i+$k) % 2`
+  --let $term     = COMMIT
+  if ($decision == 1)
+  {
+  --let $term = ROLLBACK
+  }
+  --eval XA $term '$conn_i$trx$k'
+  --let $c_max = $i2
+
+--dec $i
+}
+--enable_query_log
+--source include/save_master_gtid.inc
+
+--connection slave
+--source include/start_slave.inc
+--source include/sync_with_master_gtid.inc
+
+#
+# Overall consistency check
+#
+--let $diff_tables= master:t0, slave:t0
+--source include/diff_tables.inc
+--let $diff_tables= master:t1, slave:t1
+--source include/diff_tables.inc
+
+
+#
+# Clean up.
+#
+--connection slave
+--source include/stop_slave.inc
+set global log_warnings=default;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+--source include/start_slave.inc
+
+--connection master
+DROP VIEW v_processlist;
+DROP TABLE t0, t1;
+--source include/save_master_gtid.inc
+
+--connection slave
+--source include/sync_with_master_gtid.inc
+# Check that old rows are deleted from mysql.gtid_slave_pos.
+# Deletion is asynchronous, so use wait_condition.inc.
+# Also, there is a small amount of non-determinism in the deletion of old
+# rows, so it is not guaranteed that there can never be more than
+# @@gtid_cleanup_batch_size rows in the table; so allow a bit of slack
+# here.
+let $wait_condition=
+  SELECT COUNT(*) <= 5*@@GLOBAL.gtid_cleanup_batch_size
+    FROM mysql.gtid_slave_pos;
+--source include/wait_condition.inc
+eval $wait_condition;
+SET GLOBAL gtid_cleanup_batch_size= @old_gtid_cleanup_batch_size;
+
+--connection master
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off-slave.opt b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off-slave.opt
new file mode 100644
index 00000000000..88cf77fd281
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off-slave.opt
@@ -0,0 +1 @@
+--log-slave-updates=OFF
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off.test b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off.test
new file mode 100644
index 00000000000..f82b522eefe
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_xa_lsu_off.test
@@ -0,0 +1,2 @@
+# --log-slave-updates OFF version of rpl_parallel_optimistic_xa
+--source rpl_parallel_optimistic_xa.test
diff --git a/mysql-test/suite/rpl/t/rpl_parallel_xa_same_xid.test b/mysql-test/suite/rpl/t/rpl_parallel_xa_same_xid.test
new file mode 100644
index 00000000000..888dd2f177b
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_parallel_xa_same_xid.test
@@ -0,0 +1,138 @@
+# The tests verify concurrent execution of replicated (MDEV-742)
+# XA transactions in the parallel optimistic mode.
+# Prove optimistic scheduler handles xid-namesake XA:s.
+# That is despite running in parallel there must be no conflicts
+# caused by multiple transactions' same xid.
+
+--source include/have_binlog_format_mixed_or_row.inc
+--source include/have_innodb.inc
+--source include/have_perfschema.inc
+--source include/master-slave.inc
+
+--let $xid_num = 19
+--let $repeat  = 17
+--let $workers = 7
+--connection slave
+call mtr.add_suppression("WSREP: handlerton rollback failed");
+
+--source include/stop_slave.inc
+# a measure against MDEV-20605
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+
+SET @old_parallel_threads = @@GLOBAL.slave_parallel_threads;
+--disable_query_log
+--eval SET @@global.slave_parallel_threads  = $workers
+--enable_query_log
+SET @old_parallel_mode               = @@GLOBAL.slave_parallel_mode;
+SET @@global.slave_parallel_mode     ='optimistic';
+--source include/start_slave.inc
+
+--connection master
+CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
+
+--let $i = $xid_num
+--let $t = t1
+--disable_query_log
+while ($i)
+{
+--let $k = $repeat
+while ($k)
+{
+--eval XA START 'xid_$i'
+--eval INSERT INTO $t SET a=$i, b=$k
+--eval XA END 'xid_$i'
+--let $one_phase = `SELECT IF(floor(rand()*10)%2, "ONE PHASE", 0)`
+  if (!$one_phase)
+  {
+  --eval XA PREPARE 'xid_$i'
+  --eval XA COMMIT 'xid_$i'
+  }
+  if ($one_phase)
+  {
+  --eval XA COMMIT 'xid_$i' ONE PHASE
+  }
+
+  if (!$one_phase)
+  {
+  --eval XA START 'xid_$i'
+  --eval INSERT INTO $t SET a=$i, b=$k
+  --eval XA END 'xid_$i'
+  --eval XA PREPARE 'xid_$i'
+  --eval XA ROLLBACK 'xid_$i'
+  }
+
+--dec $k
+}
+
+--dec $i
+}
+--enable_query_log
+
+
+
+# Above-like test complicates execution env to create
+# data conflicts as well. They will be resolved by the optmistic
+# scheduler as usual.
+
+CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY, b INT) ENGINE=InnoDB;
+
+--let $i = $xid_num
+--let $t = t2
+--disable_query_log
+while ($i)
+{
+--let $k = $repeat
+while ($k)
+{
+--eval XA START 'xid_$i'
+--eval INSERT INTO $t SET a=NULL, b=$k
+--eval UPDATE $t SET b=$k + 1 WHERE a=last_insert_id() % $workers
+--eval XA END 'xid_$i'
+--let $one_phase = `SELECT IF(floor(rand()*10)%2, "ONE PHASE", 0)`
+  if (!$one_phase)
+  {
+  --eval XA PREPARE 'xid_$i'
+  --eval XA COMMIT 'xid_$i'
+  }
+  if ($one_phase)
+  {
+  --eval XA COMMIT 'xid_$i' ONE PHASE
+  }
+
+--eval XA START 'xid_$i'
+--eval UPDATE $t SET b=$k + 1 WHERE a=last_insert_id() % $workers
+--eval DELETE FROM $t WHERE a=last_insert_id()
+--eval XA END 'xid_$i'
+--eval XA PREPARE 'xid_$i'
+--eval XA ROLLBACK 'xid_$i'
+
+--let $do_drop_create = `SELECT IF(floor(rand()*10)%100, 1, 0)`
+if ($do_drop_create)
+{
+  DROP TABLE t1;
+  CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB;
+}
+--dec $k
+}
+
+--dec $i
+}
+--enable_query_log
+
+--source include/sync_slave_sql_with_master.inc
+--let $diff_tables= master:t1, slave:t1
+--source include/diff_tables.inc
+
+#
+# Clean up.
+#
+--connection slave
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=@old_parallel_threads;
+SET GLOBAL slave_parallel_mode=@old_parallel_mode;
+--source include/start_slave.inc
+
+--connection master
+DROP TABLE t1, t2;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors.test b/mysql-test/suite/rpl/t/rpl_temporary_errors.test
index 6392fb90b9b..85e16afa270 100644
--- a/mysql-test/suite/rpl/t/rpl_temporary_errors.test
+++ b/mysql-test/suite/rpl/t/rpl_temporary_errors.test
@@ -6,7 +6,7 @@ call mtr.add_suppression("Deadlock found");
 call mtr.add_suppression("Can't find record in 't.'");
 
 connection master;
-CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=innodb;
 INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4);
 sync_slave_with_master;
 SHOW STATUS LIKE 'Slave_retried_transactions';
@@ -14,20 +14,94 @@ SHOW STATUS LIKE 'Slave_retried_transactions';
 # the following UPDATE t1 to pass the mode is switched temprorarily
 set @@global.slave_exec_mode= 'IDEMPOTENT';
 UPDATE t1 SET a = 5, b = 47 WHERE a = 1;
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
 connection master;
 UPDATE t1 SET a = 5, b = 5 WHERE a = 1;
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
 #SHOW BINLOG EVENTS;
 sync_slave_with_master;
 set @@global.slave_exec_mode= default;
 SHOW STATUS LIKE 'Slave_retried_transactions';
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
 source include/check_slave_is_running.inc;
 
 connection slave;
 call mtr.add_suppression("Slave SQL.*Could not execute Update_rows event on table test.t1");
+call mtr.add_suppression("Slave SQL for channel '': worker thread retried transaction");
+call mtr.add_suppression("The slave coordinator and worker threads are stopped");
+#
+# Bug#24764800 REPLICATION FAILING ON SLAVE WITH XAER_RMFAIL ERROR
+#
+# Verify that a temporary failing replicated xa transaction completes
+# upon slave applier restart after previous
+# @@global.slave_transaction_retries number of retries in vain.
+#
+connection slave;
+
+set @save_innodb_lock_wait_timeout=@@global.innodb_lock_wait_timeout;
+set @save_slave_transaction_retries=@@global.slave_transaction_retries;
+
+# Slave applier parameters for the failed retry
+set @@global.innodb_lock_wait_timeout=1;
+set @@global.slave_transaction_retries=2;
+--source include/restart_slave_sql.inc
+
+# Temporary error implement: a record is blocked by slave local trx
+connection slave1;
+BEGIN;
+INSERT INTO t1 SET a = 6, b = 7;
+
+connection master;
+INSERT INTO t1 SET a = 99, b = 99; # slave applier warm up trx
+XA START 'xa1';
+INSERT INTO t1 SET a = 6, b = 6; # this record eventually must be found on slave
+XA END 'xa1';
+XA PREPARE 'xa1';
+
+connection slave;
+# convert_error(ER_LOCK_WAIT_TIMEOUT)
+--let $err_timeout= 1205
+# convert_error(ER_LOCK_DEADLOCK)
+--let $err_deadlock= 1213
+--let $slave_sql_errno=$err_deadlock,$err_timeout
+--let $show_slave_sql_error=
+--source include/wait_for_slave_sql_error.inc
+
+# b. Slave applier parameters for successful retry after restart
+set @@global.innodb_lock_wait_timeout=1;
+set @@global.slave_transaction_retries=100;
+
+--source include/restart_slave_sql.inc
+
+--let $last_retries= query_get_value(SHOW GLOBAL STATUS LIKE 'Slave_retried_transactions', Value, 1)
+--let $status_type=GLOBAL
+--let $status_var=Slave_retried_transactions
+--let $status_var_value=`SELECT 1 + $last_retries`
+--let $$status_var_comparsion= >
+--source include/wait_for_status_var.inc
+
+# Release the record after just one retry
+connection slave1;
+ROLLBACK;
+
+connection master;
+XA COMMIT 'xa1';
+
+--source include/sync_slave_sql_with_master.inc
+
+# Proof of correctness: the committed XA is on the slave
+connection slave;
+--let $assert_text=XA transaction record must be in the table
+--let $assert_cond=count(*)=1 FROM t1 WHERE a=6 AND b=6
+--source include/assert.inc
+
+# Bug#24764800 cleanup:
+set @@global.innodb_lock_wait_timeout=@save_innodb_lock_wait_timeout;
+set @@global.slave_transaction_retries= @save_slave_transaction_retries;
 
+#
+# Total cleanup:
+#
 connection master;
 DROP TABLE t1;
 --sync_slave_with_master
diff --git a/mysql-test/suite/rpl/t/rpl_xa.inc b/mysql-test/suite/rpl/t/rpl_xa.inc
new file mode 100644
index 00000000000..f1ba4cf8557
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa.inc
@@ -0,0 +1,73 @@
+#
+# This "body" file checks general properties of XA transaction replication
+# as of MDEV-7974.
+# Parameters:
+# --let rpl_xa_check= SELECT ...
+#
+connection master;
+create table t1 (a int, b int) engine=InnoDB;
+insert into t1 values(0, 0);
+xa start 't';
+insert into t1 values(1, 2);
+xa end 't';
+xa prepare 't';
+xa commit 't';
+
+sync_slave_with_master;
+let $diff_tables= master:t1, slave:t1;
+source include/diff_tables.inc;
+
+connection master;
+
+xa start 't';
+insert into t1 values(3, 4);
+xa end 't';
+xa prepare 't';
+xa rollback 't';
+
+sync_slave_with_master;
+let $diff_tables= master:t1, slave:t1;
+source include/diff_tables.inc;
+
+connection master;
+--disable_warnings
+SET pseudo_slave_mode=1;
+--enable_warnings
+create table t2 (a int) engine=InnoDB;
+xa start 't';
+insert into t1 values (5, 6);
+xa end 't';
+xa prepare 't';
+xa start 's';
+insert into t2 values (0);
+xa end 's';
+xa prepare 's';
+--source include/save_master_gtid.inc
+
+connection slave;
+source include/sync_with_master_gtid.inc;
+if ($rpl_xa_check)
+{
+  --eval $rpl_xa_check
+  if ($rpl_xa_verbose)
+  {
+    --eval SELECT $rpl_xa_check_lhs
+    --eval SELECT $rpl_xa_check_rhs
+  }
+}
+xa recover;
+
+connection master;
+xa commit 't';
+xa commit 's';
+--disable_warnings
+SET pseudo_slave_mode=0;
+--enable_warnings
+sync_slave_with_master;
+let $diff_tables= master:t1, slave:t1;
+source include/diff_tables.inc;
+let $diff_tables= master:t2, slave:t2;
+source include/diff_tables.inc;
+
+connection master;
+drop table t1, t2;
diff --git a/mysql-test/suite/rpl/t/rpl_xa.test b/mysql-test/suite/rpl/t/rpl_xa.test
new file mode 100644
index 00000000000..05a1abe59ae
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa.test
@@ -0,0 +1,5 @@
+source include/have_innodb.inc;
+source include/master-slave.inc;
+
+source rpl_xa.inc;
+source include/rpl_end.inc;
diff --git a/mysql-test/suite/rpl/t/rpl_xa_gap_lock-slave.opt b/mysql-test/suite/rpl/t/rpl_xa_gap_lock-slave.opt
new file mode 100644
index 00000000000..4602a43ce25
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_gap_lock-slave.opt
@@ -0,0 +1 @@
+--transaction-isolation=READ-COMMITTED
diff --git a/mysql-test/suite/rpl/t/rpl_xa_gap_lock.test b/mysql-test/suite/rpl/t/rpl_xa_gap_lock.test
new file mode 100644
index 00000000000..9c48891b889
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_gap_lock.test
@@ -0,0 +1,137 @@
+# ==== Purpose ====
+#
+# This test will generate two XA transactions on the master in a way that
+# they will block each other on the slave if the transaction isolation level
+# used by the slave applier is more restrictive than the READ COMMITTED one.
+#
+# Consider:
+#   E=execute, P=prepare, C=commit;
+#   1=first transaction, 2=second transaction;
+#
+# Master does: E1, E2, P2, P1, C1, C2
+# Slave does:  E2, P2, E1, P1, C1, C2
+#
+# The transactions are designed so that, if the applier transaction isolation
+# level is more restrictive than the READ COMMITTED, E1 will be blocked on
+# the slave waiting for gap locks to be released.
+#
+# Step 1
+#
+# The test will verify that the transactions don't block each other because
+# the applier thread automatically changed the isolation level.
+#
+# Step 2
+#
+# The test will verify that applying master's binary log dump in slave doesn't
+# block because mysqlbinlog is informing the isolation level to be used.
+#
+# ==== Related Bugs and Worklogs ====
+#
+# BUG#25040331: INTERLEAVED XA TRANSACTIONS MAY DEADLOCK SLAVE APPLIER WITH
+#               REPEATABLE READ
+#
+--source include/have_debug.inc
+--source include/have_innodb.inc
+# The test case only make sense for RBR
+--source include/have_binlog_format_row.inc
+--source include/master-slave.inc
+
+--connection slave
+# To hit the issue, we need to split the data in two pages.
+# This global variable will help us.
+SET @saved_innodb_limit_optimistic_insert_debug = @@GLOBAL.innodb_limit_optimistic_insert_debug;
+SET @@GLOBAL.innodb_limit_optimistic_insert_debug = 2;
+
+#
+# Step 1 - Using async replication
+#
+
+# Let's generate the workload on the master
+--connection master
+CREATE TABLE t1 (
+  c1 INT NOT NULL,
+  KEY(c1)
+) ENGINE=InnoDB;
+
+CREATE TABLE t2 (
+  c1 INT NOT NULL,
+  FOREIGN KEY(c1) REFERENCES t1(c1)
+) ENGINE=InnoDB;
+
+INSERT INTO t1 VALUES (1), (3), (4);
+
+--connection master1
+XA START 'XA1';
+INSERT INTO t1 values(2);
+XA END 'XA1';
+
+# This transaction will reference the gap where XA1
+# was inserted, and will be prepared and committed
+# before XA1, so the slave will prepare it (but will
+# not commit it) before preparing XA1.
+--connection master
+XA START 'XA2';
+INSERT INTO t2 values(3);
+XA END 'XA2';
+
+# The XA2 prepare should be binary logged first
+XA PREPARE 'XA2';
+
+# The XA1 prepare should be binary logged
+# after XA2 prepare and before XA2 commit.
+--connection master1
+XA PREPARE 'XA1';
+
+# The commit order doesn't matter much for the issue being tested.
+XA COMMIT 'XA1';
+--connection master
+XA COMMIT 'XA2';
+
+# Everything is fine if the slave can sync with the master.
+--source include/sync_slave_sql_with_master.inc
+
+#
+# Step 2 - Using mysqlbinlog dump to restore the salve
+#
+--source include/stop_slave.inc
+DROP TABLE t2, t1;
+RESET SLAVE;
+RESET MASTER;
+
+--connection master
+--let $master_data_dir= `SELECT @@datadir`
+--let $master_log_file= query_get_value(SHOW MASTER STATUS, File, 1)
+--let $mysql_server= $MYSQL --defaults-group-suffix=.2
+--echo Restore binary log from the master into the slave
+--exec $MYSQL_BINLOG --force-if-open $master_data_dir/$master_log_file | $mysql_server
+
+--let $diff_tables= master:test.t1, slave:test.t1
+--source include/diff_tables.inc
+--let $diff_tables= master:test.t2, slave:test.t2
+--source include/diff_tables.inc
+
+#
+# Cleanup
+#
+--let $master_file= query_get_value(SHOW MASTER STATUS, File, 1)
+--let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1)
+DROP TABLE t2, t1;
+
+## When GTID_MODE=OFF, we need to skip already applied transactions
+--connection slave
+#--let $gtid_mode= `SELECT @@GTID_MODE`
+#if ($gtid_mode == OFF)
+#{
+#  --disable_query_log
+#  --disable_result_log
+#  --eval CHANGE MASTER TO MASTER_LOG_FILE='$master_file', MASTER_LOG_POS=$master_pos
+#  --enable_result_log
+#  --enable_query_log
+#}
+--replace_result $master_file LOG_FILE $master_pos LOG_POS
+--eval CHANGE MASTER TO MASTER_LOG_FILE='$master_file', MASTER_LOG_POS=$master_pos
+ 
+SET @@GLOBAL.innodb_limit_optimistic_insert_debug = @saved_innodb_limit_optimistic_insert_debug;
+--source include/start_slave.inc
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_xa_gtid_pos_auto_engine.test b/mysql-test/suite/rpl/t/rpl_xa_gtid_pos_auto_engine.test
new file mode 100644
index 00000000000..b83493762c3
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_gtid_pos_auto_engine.test
@@ -0,0 +1,29 @@
+--source include/have_innodb.inc
+--source include/master-slave.inc
+
+--connection slave
+call mtr.add_suppression("The automatically created table.*name may not be entirely in lowercase");
+
+--source include/stop_slave.inc
+CHANGE MASTER TO master_use_gtid=slave_pos;
+
+SET @@global.gtid_pos_auto_engines="innodb";
+--source include/start_slave.inc
+--let $rpl_xa_check_lhs= @@global.gtid_slave_pos
+--let $rpl_xa_check_rhs= CONCAT(domain_id,"-",server_id,"-",seq_no) FROM mysql.gtid_slave_pos WHERE seq_no = (SELECT DISTINCT max(seq_no) FROM mysql.gtid_slave_pos)
+--let $rpl_xa_check=SELECT $rpl_xa_check_lhs = $rpl_xa_check_rhs
+--source rpl_xa.inc
+
+--connection slave
+--source include/stop_slave.inc
+SET @@global.gtid_pos_auto_engines="";
+SET @@session.sql_log_bin=0;
+DROP TABLE mysql.gtid_slave_pos_InnoDB;
+if (`SHOW COUNT(*) WARNINGS`)
+{
+  show tables in mysql like 'gtid_slave_pos%';
+}
+SET @@session.sql_log_bin=1;
+--source include/start_slave.inc
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect.test b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect.test
new file mode 100644
index 00000000000..1c33435473e
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect.test
@@ -0,0 +1,294 @@
+#   BUG #12161 Xa recovery and client disconnection
+#    the test verifies that
+#    a. disconnection does not lose a prepared transaction
+#        so it can be committed from another connection
+#    c. the prepared transaction is logged
+#    d. interleaved prepared transactions are correctly applied on the slave.
+
+#
+# Both replication format are checked through explict
+# set @@binlog_format in the test.
+#
+--source include/have_innodb.inc
+--source include/have_binlog_format_mixed.inc
+#
+# Prepared XA can't get available to an external connection
+# until a connection, that either leaves actively or is killed,
+# has completed a necessary part of its cleanup.
+# Selecting from P_S.threads provides a method to learn that.
+#
+--source include/have_perfschema.inc
+--source include/master-slave.inc
+
+--connection master
+call mtr.add_suppression("Found 2 prepared XA transactions");
+CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';
+
+CREATE DATABASE d1;
+CREATE DATABASE d2;
+
+CREATE TABLE d1.t (a INT) ENGINE=innodb;
+CREATE TABLE d2.t (a INT) ENGINE=innodb;
+
+connect (master_conn1, 127.0.0.1,root,,test,$MASTER_MYPORT,);
+--let $conn_id=`SELECT connection_id()`
+SET @@session.binlog_format= statement;
+XA START '1-stmt';
+INSERT INTO d1.t VALUES (1);
+XA END '1-stmt';
+XA PREPARE '1-stmt';
+
+--disconnect master_conn1
+
+--connection master
+
+--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id
+--source include/wait_condition.inc
+
+connect (master_conn2, 127.0.0.1,root,,test,$MASTER_MYPORT,);
+--let $conn_id=`SELECT connection_id()`
+SET @@session.binlog_format= row;
+XA START '1-row';
+INSERT INTO d2.t VALUES (1);
+XA END '1-row';
+XA PREPARE '1-row';
+
+--disconnect master_conn2
+
+--connection master
+--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id
+--source include/wait_condition.inc
+
+XA START '2';
+INSERT INTO d1.t VALUES (2);
+XA END '2';
+XA PREPARE '2';
+XA COMMIT '2';
+
+XA COMMIT '1-row';
+XA COMMIT '1-stmt';
+source include/show_binlog_events.inc;
+
+# the proof: slave is in sync with the table updated by the prepared transactions.
+--source include/sync_slave_sql_with_master.inc
+
+--source include/stop_slave.inc
+
+#
+# Recover with Master server restart
+#
+--connection master
+
+connect (master2, 127.0.0.1,root,,test,$MASTER_MYPORT,);
+--connection master2
+SET @@session.binlog_format= statement;
+XA START '3-stmt';
+INSERT INTO d1.t VALUES (3);
+XA END '3-stmt';
+XA PREPARE '3-stmt';
+--disconnect master2
+
+connect (master2, 127.0.0.1,root,,test,$MASTER_MYPORT,);
+--connection master2
+SET @@session.binlog_format= row;
+XA START '3-row';
+INSERT INTO d2.t VALUES (4);
+XA END '3-row';
+XA PREPARE '3-row';
+--disconnect master2
+
+--connection master
+
+#
+# Testing read-only
+#
+connect (master2, 127.0.0.1,root,,test,$MASTER_MYPORT,);
+--connection master2
+XA START '4';
+SELECT * FROM d1.t;
+XA END '4';
+XA PREPARE '4';
+--disconnect master2
+
+#
+# Logging few disconnected XA:s for replication.
+#
+--let $bulk_trx_num=10
+--let $i = $bulk_trx_num
+
+while($i > 0)
+{
+  --connect (master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,)
+  --let $conn_id=`SELECT connection_id()`
+
+  --eval XA START 'bulk_trx_$i'
+  --eval INSERT INTO d1.t VALUES ($i)
+  --eval INSERT INTO d2.t VALUES ($i)
+  --eval XA END 'bulk_trx_$i'
+  --eval XA PREPARE 'bulk_trx_$i'
+
+  --disconnect master_bulk_conn$i
+
+  --connection master
+  --let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id
+   --source include/wait_condition.inc
+
+  --dec $i
+}
+
+#
+# Prove the slave applier is capable to resume the prepared XA:s
+# upon its restart.
+#
+--connection slave
+--source include/start_slave.inc
+--connection master
+--source include/sync_slave_sql_with_master.inc
+--source include/stop_slave.inc
+
+--connection master
+--let $i = $bulk_trx_num
+while($i > 0)
+{
+  --let $command=COMMIT
+  if (`SELECT $i % 2`)
+  {
+    --let $command=ROLLBACK
+  }
+  --eval XA $command 'bulk_trx_$i'
+  --dec $i
+}
+
+--let $rpl_server_number= 1
+--source include/rpl_restart_server.inc
+
+--connection slave
+--source include/start_slave.inc
+
+--connection master
+--echo *** '3-stmt','3-row' xa-transactions must be in the list ***
+XA RECOVER;
+XA COMMIT '3-stmt';
+XA ROLLBACK '3-row';
+
+--source include/sync_slave_sql_with_master.inc
+
+#
+# Testing replication with marginal XID values and in two formats.
+#
+
+--connection master
+--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id
+--source include/wait_condition.inc
+
+# Max size XID incl max value of formatID
+connect (master_conn2, 127.0.0.1,root,,test,$MASTER_MYPORT,);
+--let $conn_id=`SELECT connection_id()`
+
+--let $gtrid=0123456789012345678901234567890123456789012345678901234567890124
+--let $bqual=0123456789012345678901234567890123456789012345678901234567890124
+--eval XA START '$gtrid','$bqual',4294967292
+       INSERT INTO d1.t VALUES (64);
+--eval XA END '$gtrid','$bqual',4294967292
+--eval XA PREPARE '$gtrid','$bqual',4294967292
+
+--disconnect master_conn2
+
+--connection master
+--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id
+--source include/wait_condition.inc
+
+# Max size XID with non-ascii chars
+connect (master_conn3, 127.0.0.1,root,,test,$MASTER_MYPORT,);
+--let $conn_id=`SELECT connection_id()`
+
+--let $gtrid_hex=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+--let $bqual_hex=00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+--eval XA START X'$gtrid_hex',X'$bqual_hex',0
+       INSERT INTO d1.t VALUES (0);
+--eval XA END X'$gtrid_hex',X'$bqual_hex',0
+--eval XA PREPARE X'$gtrid_hex',X'$bqual_hex',0
+
+--disconnect master_conn3
+
+--connection master
+--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id
+--source include/wait_condition.inc
+
+# Random XID
+--disable_query_log
+
+connect (master_conn4, 127.0.0.1,root,,test,$MASTER_MYPORT,);
+--let $conn_id=`SELECT connection_id()`
+
+--let $gtridlen=`SELECT 2*(1 + round(rand()*100) % 31)`
+--let $bquallen=`SELECT 2*(1 + round(rand()*100) % 31)`
+--let $gtrid_rand=`SELECT substring(concat(MD5(rand()), MD5(rand())), 1, $gtridlen)`
+--let $bqual_rand=`SELECT substring(concat(MD5(rand()), MD5(rand())), 1, $bquallen)`
+--let $formt_rand=`SELECT floor((rand()*10000000000) % 4294967293)`
+--eval XA START X'$gtrid_rand',X'$bqual_rand',$formt_rand
+       INSERT INTO d1.t VALUES (0);
+--eval XA END X'$gtrid_rand',X'$bqual_rand',$formt_rand
+--eval XA PREPARE X'$gtrid_rand',X'$bqual_rand',$formt_rand
+
+--enable_query_log
+
+--disconnect master_conn4
+
+--connection master
+--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn_id
+--source include/wait_condition.inc
+
+--eval XA COMMIT '$gtrid','$bqual',4294967292
+--eval XA COMMIT X'$gtrid_hex',X'$bqual_hex',0
+--disable_query_log
+--echo XA COMMIT 'RANDOM XID'
+--eval XA COMMIT X'$gtrid_rand',X'$bqual_rand',$formt_rand
+--enable_query_log
+
+--source include/sync_slave_sql_with_master.inc
+
+#
+# Testing ONE PHASE
+#
+--let $onephase_trx_num=10
+--let $i = $onephase_trx_num
+while($i > 0)
+{
+  --connect (master_bulk_conn$i, 127.0.0.1,root,,test,$MASTER_MYPORT,)
+
+  --connection master_bulk_conn$i
+  --eval XA START 'one_phase_$i'
+  --eval INSERT INTO d1.t VALUES ($i)
+  --eval INSERT INTO d2.t VALUES ($i)
+  --eval XA END 'one_phase_$i'
+  --eval XA COMMIT 'one_phase_$i' ONE PHASE
+
+  --disconnect master_bulk_conn$i
+  --dec $i
+}
+--connection master
+--source include/sync_slave_sql_with_master.inc
+
+#
+# Overall consistency check
+#
+--let $diff_tables= master:d1.t, slave:d1.t
+--source include/diff_tables.inc
+--let $diff_tables= master:d2.t, slave:d2.t
+--source include/diff_tables.inc
+#
+# cleanup
+#
+--connection master
+
+DELETE FROM d1.t;
+DELETE FROM d2.t;
+DROP TABLE d1.t, d2.t;
+DROP DATABASE d1;
+DROP DATABASE d2;
+DROP VIEW v_processlist;
+
+--source include/sync_slave_sql_with_master.inc
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off-slave.opt b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off-slave.opt
new file mode 100644
index 00000000000..94c3650024f
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off-slave.opt
@@ -0,0 +1,2 @@
+--log-slave-updates=off
+
diff --git a/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off.test b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off.test
new file mode 100644
index 00000000000..df3811df6ae
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_lsu_off.test
@@ -0,0 +1,8 @@
+# ==== Purpose ====
+# 'rpl_xa_survive_disconnect_lsu_off' verifies the same properties as the sourced file
+# in conditions of the slave does not log own updates
+# (lsu in the name stands for log_slave_updates).
+# Specifically this mode aims at proving correct operations on the slave
+# mysql.gtid_executed.
+
+--source ./rpl_xa_survive_disconnect.test
diff --git a/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_mixed_engines.test b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_mixed_engines.test
new file mode 100644
index 00000000000..f52a9630a87
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_survive_disconnect_mixed_engines.test
@@ -0,0 +1,68 @@
+# BUG#12161 Xa recovery and client disconnection
+#
+# The test verifies correct XA transaction two phase logging and its applying
+# in a case the transaction updates transactional and non-transactional tables.
+# Transactions are terminated according to specfied parameters to
+# a sourced inc-file.
+
+--source include/have_innodb.inc
+--source include/master-slave.inc
+
+--connection master
+CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
+
+--let $command=setup
+--source include/rpl_xa_mixed_engines.inc
+
+--echo === COMMIT ===
+--let $command=run
+--let $xa_terminate=XA COMMIT
+--let $xa_prepare_opt=1
+--source include/rpl_xa_mixed_engines.inc
+
+--source include/sync_slave_sql_with_master.inc
+--connection master
+
+--echo === COMMIT ONE PHASE ===
+
+--let $command=run
+--let $xa_terminate=XA COMMIT
+--let $one_phase=ONE PHASE
+--let $xa_prepare_opt=
+--source include/rpl_xa_mixed_engines.inc
+--let $one_phase=
+--source include/sync_slave_sql_with_master.inc
+--connection master
+
+--echo === ROLLBACK with PREPARE ===
+
+--let $command=run
+--let $xa_terminate=xa rollback
+--let $xa_prepare_opt=1
+--source include/rpl_xa_mixed_engines.inc
+
+--source include/sync_slave_sql_with_master.inc
+--connection master
+
+--echo === ROLLBACK with no PREPARE ===
+
+--let $command=run
+--let $xa_terminate=xa rollback
+--let $xa_prepare_opt=
+--source include/rpl_xa_mixed_engines.inc
+--let $xa_rollback_only=
+
+--source include/sync_slave_sql_with_master.inc
+
+--let $diff_tables= master:tm, slave:tm
+--source include/diff_tables.inc
+
+# Cleanup
+
+--connection master
+--let $command=cleanup
+--source include/rpl_xa_mixed_engines.inc
+
+--source include/sync_slave_sql_with_master.inc
+
+--source include/rpl_end.inc
diff --git a/sql/handler.cc b/sql/handler.cc
index 7d61252eea6..c72386c7e99 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1300,6 +1300,14 @@ int ha_prepare(THD *thd)
 
       }
     }
+
+    DEBUG_SYNC(thd, "at_unlog_xa_prepare");
+
+    if (tc_log->unlog_xa_prepare(thd, all))
+    {
+      ha_rollback_trans(thd, all);
+      error=1;
+    }
   }
 
   DBUG_RETURN(error);
@@ -1853,7 +1861,8 @@ int ha_rollback_trans(THD *thd, bool all)
       rollback without signalling following transactions. And in release
       builds, we explicitly do the signalling before rolling back.
     */
-    DBUG_ASSERT(!(thd->rgi_slave && thd->rgi_slave->did_mark_start_commit));
+    DBUG_ASSERT(!(thd->rgi_slave && thd->rgi_slave->did_mark_start_commit) ||
+                thd->transaction.xid_state.is_explicit_XA());
     if (thd->rgi_slave && thd->rgi_slave->did_mark_start_commit)
       thd->rgi_slave->unmark_start_commit();
   }
diff --git a/sql/log.cc b/sql/log.cc
index 56e83bf2448..e13f8fbc88f 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -91,7 +91,13 @@ static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton,
 static int binlog_commit(handlerton *hton, THD *thd, bool all);
 static int binlog_rollback(handlerton *hton, THD *thd, bool all);
 static int binlog_prepare(handlerton *hton, THD *thd, bool all);
+static int binlog_xa_recover_dummy(handlerton *hton, XID *xid_list, uint len);
+static int binlog_commit_by_xid(handlerton *hton, XID *xid);
+static int binlog_rollback_by_xid(handlerton *hton, XID *xid);
 static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd);
+static int binlog_flush_cache(THD *thd, binlog_cache_mngr *cache_mngr,
+                              Log_event *end_ev, bool all, bool using_stmt,
+                              bool using_trx);
 
 static const LEX_CSTRING write_error_msg=
     { STRING_WITH_LEN("error writing to the binary log") };
@@ -1693,6 +1699,10 @@ int binlog_init(void *p)
   {
     binlog_hton->prepare= binlog_prepare;
     binlog_hton->start_consistent_snapshot= binlog_start_consistent_snapshot;
+    binlog_hton->commit_by_xid= binlog_commit_by_xid;
+    binlog_hton->rollback_by_xid= binlog_rollback_by_xid;
+    // recover needs to be set to make xa{commit,rollback}_handlerton effective
+    binlog_hton->recover= binlog_xa_recover_dummy;
   }
   binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
   return 0;
@@ -1765,7 +1775,8 @@ binlog_flush_cache(THD *thd, binlog_cache_mngr *cache_mngr,
   DBUG_PRINT("enter", ("end_ev: %p", end_ev));
 
   if ((using_stmt && !cache_mngr->stmt_cache.empty()) ||
-      (using_trx && !cache_mngr->trx_cache.empty()))
+      (using_trx && !cache_mngr->trx_cache.empty())   ||
+      thd->transaction.xid_state.is_explicit_XA())
   {
     if (using_stmt && thd->binlog_flush_pending_rows_event(TRUE, FALSE))
       DBUG_RETURN(1);
@@ -1837,6 +1848,17 @@ binlog_commit_flush_stmt_cache(THD *thd, bool all,
   DBUG_RETURN(binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, FALSE));
 }
 
+
+inline size_t serialize_with_xid(XID *xid, char *buf,
+                                 const char *query, size_t q_len)
+{
+  memcpy(buf, query, q_len);
+
+  return
+    q_len + strlen(static_cast<event_xid_t*>(xid)->serialize(buf + q_len));
+}
+
+
 /**
   This function flushes the trx-cache upon commit.
 
@@ -1850,11 +1872,28 @@ static inline int
 binlog_commit_flush_trx_cache(THD *thd, bool all, binlog_cache_mngr *cache_mngr)
 {
   DBUG_ENTER("binlog_commit_flush_trx_cache");
-  Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
-                          TRUE, TRUE, TRUE, 0);
+
+  const char query[]= "XA COMMIT ";
+  const size_t q_len= sizeof(query) - 1; // do not count trailing 0
+  char buf[q_len + ser_buf_size]= "COMMIT";
+  size_t buflen= sizeof("COMMIT") - 1;
+
+  if (thd->lex->sql_command == SQLCOM_XA_COMMIT &&
+      thd->lex->xa_opt != XA_ONE_PHASE)
+  {
+    DBUG_ASSERT(thd->transaction.xid_state.is_explicit_XA());
+    DBUG_ASSERT(thd->transaction.xid_state.get_state_code() ==
+                XA_PREPARED);
+
+    buflen= serialize_with_xid(thd->transaction.xid_state.get_xid(),
+                               buf, query, q_len);
+  }
+  Query_log_event end_evt(thd, buf, buflen, TRUE, TRUE, TRUE, 0);
+
   DBUG_RETURN(binlog_flush_cache(thd, cache_mngr, &end_evt, all, FALSE, TRUE));
 }
 
+
 /**
   This function flushes the trx-cache upon rollback.
 
@@ -1868,8 +1907,20 @@ static inline int
 binlog_rollback_flush_trx_cache(THD *thd, bool all,
                                 binlog_cache_mngr *cache_mngr)
 {
-  Query_log_event end_evt(thd, STRING_WITH_LEN("ROLLBACK"),
-                          TRUE, TRUE, TRUE, 0);
+  const char query[]= "XA ROLLBACK ";
+  const size_t q_len= sizeof(query) - 1; // do not count trailing 0
+  char buf[q_len + ser_buf_size]= "ROLLBACK";
+  size_t buflen= sizeof("ROLLBACK") - 1;
+
+  if (thd->transaction.xid_state.is_explicit_XA())
+  {
+    /* for not prepared use plain ROLLBACK */
+    if (thd->transaction.xid_state.get_state_code() == XA_PREPARED)
+      buflen= serialize_with_xid(thd->transaction.xid_state.get_xid(),
+                                 buf, query, q_len);
+  }
+  Query_log_event end_evt(thd, buf, buflen, TRUE, TRUE, TRUE, 0);
+
   return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, FALSE, TRUE));
 }
 
@@ -1887,23 +1938,10 @@ static inline int
 binlog_commit_flush_xid_caches(THD *thd, binlog_cache_mngr *cache_mngr,
                                bool all, my_xid xid)
 {
-  if (xid)
-  {
-    Xid_log_event end_evt(thd, xid, TRUE);
-    return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
-  }
-  else
-  {
-    /*
-      Empty xid occurs in XA COMMIT ... ONE PHASE.
-      In this case, we do not have a MySQL xid for the transaction, and the
-      external XA transaction coordinator will have to handle recovery if
-      needed. So we end the transaction with a plain COMMIT query event.
-    */
-    Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
-                            TRUE, TRUE, TRUE, 0);
-    return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
-  }
+  DBUG_ASSERT(xid); // replaced former treatment of ONE-PHASE XA
+
+  Xid_log_event end_evt(thd, xid, TRUE);
+  return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
 }
 
 /**
@@ -1959,17 +1997,67 @@ binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
   DBUG_RETURN(error);
 }
 
+
+inline bool is_preparing_xa(THD *thd)
+{
+  return
+    thd->transaction.xid_state.is_explicit_XA() &&
+    thd->lex->sql_command == SQLCOM_XA_PREPARE;
+}
+
+
 static int binlog_prepare(handlerton *hton, THD *thd, bool all)
 {
   /*
-    do nothing.
-    just pretend we can do 2pc, so that MySQL won't
-    switch to 1pc.
-    real work will be done in MYSQL_BIN_LOG::log_and_order()
+    Do nothing unless the transaction is a user XA.
   */
+  return
+    !is_preparing_xa(thd) ? 0 : binlog_commit(NULL, thd, all);
+}
+
+
+static int binlog_xa_recover_dummy(handlerton *hton __attribute__((unused)),
+                             XID *xid_list __attribute__((unused)),
+                             uint len __attribute__((unused)))
+{
+  /* Does nothing. */
   return 0;
 }
 
+
+static int binlog_commit_by_xid(handlerton *hton, XID *xid)
+{
+  THD *thd= current_thd;
+
+  if (thd->transaction.xid_state.is_binlogged())
+    (void) thd->binlog_setup_trx_data();
+
+  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_COMMIT);
+
+  return binlog_commit(hton, thd, TRUE);
+}
+
+
+static int binlog_rollback_by_xid(handlerton *hton, XID *xid)
+{
+  THD *thd= current_thd;
+
+  if (thd->transaction.xid_state.is_binlogged())
+    (void) thd->binlog_setup_trx_data();
+
+  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_XA_ROLLBACK);
+
+  return binlog_rollback(hton, thd, TRUE);
+}
+
+
+inline bool is_prepared_xa(THD *thd)
+{
+  return thd->transaction.xid_state.is_explicit_XA() &&
+    thd->transaction.xid_state.get_state_code() == XA_PREPARED;
+}
+
+
 /*
   We flush the cache wrapped in a beging/rollback if:
     . aborting a single or multi-statement transaction and;
@@ -1992,7 +2080,55 @@ static bool trans_cannot_safely_rollback(THD *thd, bool all)
            thd->wsrep_binlog_format() == BINLOG_FORMAT_MIXED) ||
           (trans_has_updated_non_trans_table(thd) &&
            ending_single_stmt_trans(thd,all) &&
-           thd->wsrep_binlog_format() == BINLOG_FORMAT_MIXED));
+           thd->wsrep_binlog_format() == BINLOG_FORMAT_MIXED) ||
+          is_prepared_xa(thd));
+}
+
+
+/**
+  Specific log flusher invoked through log_xa_prepare().
+*/
+static int binlog_commit_flush_xa_prepare(THD *thd, bool all,
+                                          binlog_cache_mngr *cache_mngr)
+{
+  XID *xid= thd->transaction.xid_state.get_xid();
+  {
+    // todo assert wsrep_simulate || is_open()
+
+    /*
+      Log the XA END event first.
+      We don't do that in trans_xa_end() as XA COMMIT ONE PHASE
+      is logged as simple BEGIN/COMMIT so the XA END should
+      not get to the log.
+    */
+    const char query[]= "XA END ";
+    const size_t q_len= sizeof(query) - 1; // do not count trailing 0
+    char buf[q_len + ser_buf_size];
+    size_t buflen;
+    binlog_cache_data *cache_data;
+    IO_CACHE *file;
+
+    memcpy(buf, query, q_len);
+    buflen= q_len +
+      strlen(static_cast<event_xid_t*>(xid)->serialize(buf + q_len));
+    cache_data= cache_mngr->get_binlog_cache_data(true);
+    file= &cache_data->cache_log;
+    thd->lex->sql_command= SQLCOM_XA_END;
+    Query_log_event xa_end(thd, buf, buflen, true, false, true, 0);
+    if (mysql_bin_log.write_event(&xa_end, cache_data, file))
+      return 1;
+    thd->lex->sql_command= SQLCOM_XA_PREPARE;
+  }
+
+  cache_mngr->using_xa= FALSE;
+  XA_prepare_log_event end_evt(thd, xid, FALSE);
+  /*
+    Memorize the fact of prepare-logging to recall at commit
+    possibly from another session.
+  */
+  if (thd->variables.option_bits & OPTION_BIN_LOG)
+    thd->transaction.xid_state.set_binlogged();
+  return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, TRUE));
 }
 
 
@@ -2019,7 +2155,9 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
 
   if (!cache_mngr)
   {
-    DBUG_ASSERT(WSREP(thd));
+    DBUG_ASSERT(WSREP(thd) ||
+                (thd->transaction.xid_state.is_explicit_XA() &&
+                 !thd->transaction.xid_state.is_binlogged()));
     DBUG_RETURN(0);
   }
 
@@ -2038,7 +2176,8 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
     error= binlog_commit_flush_stmt_cache(thd, all, cache_mngr);
   }
 
-  if (cache_mngr->trx_cache.empty())
+  if (cache_mngr->trx_cache.empty() &&
+      !thd->transaction.xid_state.is_binlogged())
   {
     /*
       we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
@@ -2055,8 +2194,11 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
     Otherwise, we accumulate the changes.
   */
   if (likely(!error) && ending_trans(thd, all))
-    error= binlog_commit_flush_trx_cache(thd, all, cache_mngr);
-
+  {
+    error= !is_preparing_xa(thd) ?
+      binlog_commit_flush_trx_cache (thd, all, cache_mngr) :
+      binlog_commit_flush_xa_prepare(thd, all, cache_mngr);
+  }
   /*
     This is part of the stmt rollback.
   */
@@ -2080,13 +2222,16 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
 static int binlog_rollback(handlerton *hton, THD *thd, bool all)
 {
   DBUG_ENTER("binlog_rollback");
+
   int error= 0;
   binlog_cache_mngr *const cache_mngr=
     (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
 
   if (!cache_mngr)
   {
-    DBUG_ASSERT(WSREP(thd));
+    DBUG_ASSERT(WSREP(thd) ||
+                (is_prepared_xa(thd) ||
+                 !thd->transaction.xid_state.is_binlogged()));
     DBUG_RETURN(0);
   }
 
@@ -2101,15 +2246,16 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
   */
   if (cache_mngr->stmt_cache.has_incident())
   {
-    error= mysql_bin_log.write_incident(thd);
+    error |= static_cast<int>(mysql_bin_log.write_incident(thd));
     cache_mngr->reset(true, false);
   }
   else if (!cache_mngr->stmt_cache.empty())
   {
-    error= binlog_commit_flush_stmt_cache(thd, all, cache_mngr);
+    error |= binlog_commit_flush_stmt_cache(thd, all, cache_mngr);
   }
 
-  if (cache_mngr->trx_cache.empty())
+  if (cache_mngr->trx_cache.empty() &&
+      !thd->transaction.xid_state.is_binlogged())
   {
     /*
       we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
@@ -7340,10 +7486,10 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd,
   entry.all= all;
   entry.using_stmt_cache= using_stmt_cache;
   entry.using_trx_cache= using_trx_cache;
-  entry.need_unlog= false;
+  entry.need_unlog= is_preparing_xa(thd);
   ha_info= all ? thd->transaction.all.ha_list : thd->transaction.stmt.ha_list;
 
-  for (; ha_info; ha_info= ha_info->next())
+  for (; !entry.need_unlog && ha_info; ha_info= ha_info->next())
   {
     if (ha_info->is_started() && ha_info->ht() != binlog_hton &&
         !ha_info->ht()->commit_checkpoint_request)
@@ -7916,7 +8062,9 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
         We already checked before that at least one cache is non-empty; if both
         are empty we would have skipped calling into here.
       */
-      DBUG_ASSERT(!cache_mngr->stmt_cache.empty() || !cache_mngr->trx_cache.empty());
+      DBUG_ASSERT(!cache_mngr->stmt_cache.empty() ||
+                  !cache_mngr->trx_cache.empty()  ||
+                  current->thd->transaction.xid_state.is_explicit_XA());
 
       if (unlikely((current->error= write_transaction_or_stmt(current,
                                                               commit_id))))
@@ -7925,7 +8073,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
       strmake_buf(cache_mngr->last_commit_pos_file, log_file_name);
       commit_offset= my_b_write_tell(&log_file);
       cache_mngr->last_commit_pos_offset= commit_offset;
-      if (cache_mngr->using_xa && cache_mngr->xa_xid)
+      if ((cache_mngr->using_xa && cache_mngr->xa_xid) || current->need_unlog)
       {
         /*
           If all storage engines support commit_checkpoint_request(), then we
@@ -8160,7 +8308,8 @@ MYSQL_BIN_LOG::write_transaction_or_stmt(group_commit_entry *entry,
   binlog_cache_mngr *mngr= entry->cache_mngr;
   DBUG_ENTER("MYSQL_BIN_LOG::write_transaction_or_stmt");
 
-  if (write_gtid_event(entry->thd, false, entry->using_trx_cache, commit_id))
+  if (write_gtid_event(entry->thd, is_prepared_xa(entry->thd),
+                       entry->using_trx_cache, commit_id))
     DBUG_RETURN(ER_ERROR_ON_WRITE);
 
   if (entry->using_stmt_cache && !mngr->stmt_cache.empty() &&
@@ -9862,6 +10011,24 @@ int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
   DBUG_RETURN(BINLOG_COOKIE_GET_ERROR_FLAG(cookie));
 }
 
+
+int TC_LOG_BINLOG::unlog_xa_prepare(THD *thd, bool all)
+{
+  DBUG_ASSERT(is_preparing_xa(thd));
+
+  binlog_cache_mngr *cache_mngr= thd->binlog_setup_trx_data();
+  int cookie= 0;
+
+  if (!cache_mngr || !cache_mngr->need_unlog)
+    return 0;
+  else
+    cookie= BINLOG_COOKIE_MAKE(cache_mngr->binlog_id, cache_mngr->delayed_error);
+  cache_mngr->need_unlog= false;
+
+  return unlog(cookie, 1);
+}
+
+
 void
 TC_LOG_BINLOG::commit_checkpoint_notify(void *cookie)
 {
@@ -10178,6 +10345,7 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
           ((last_gtid_standalone && !ev->is_part_of_group(typ)) ||
            (!last_gtid_standalone &&
             (typ == XID_EVENT ||
+             typ == XA_PREPARE_LOG_EVENT ||
              (LOG_EVENT_IS_QUERY(typ) &&
               (((Query_log_event *)ev)->is_commit() ||
                ((Query_log_event *)ev)->is_rollback()))))))
diff --git a/sql/log.h b/sql/log.h
index 8684eaba786..8e70d3c8f4c 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -61,6 +61,7 @@ class TC_LOG
                             bool need_prepare_ordered,
                             bool need_commit_ordered) = 0;
   virtual int unlog(ulong cookie, my_xid xid)=0;
+  virtual int unlog_xa_prepare(THD *thd, bool all)= 0;
   virtual void commit_checkpoint_notify(void *cookie)= 0;
 
 protected:
@@ -115,6 +116,10 @@ class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging
     return 1;
   }
   int unlog(ulong cookie, my_xid xid)  { return 0; }
+  int unlog_xa_prepare(THD *thd, bool all)
+  {
+    return 0;
+  }
   void commit_checkpoint_notify(void *cookie) { DBUG_ASSERT(0); };
 };
 
@@ -198,6 +203,10 @@ class TC_LOG_MMAP: public TC_LOG
   int log_and_order(THD *thd, my_xid xid, bool all,
                     bool need_prepare_ordered, bool need_commit_ordered);
   int unlog(ulong cookie, my_xid xid);
+  int unlog_xa_prepare(THD *thd, bool all)
+  {
+    return 0;
+  }
   void commit_checkpoint_notify(void *cookie);
   int recover();
 
@@ -695,6 +704,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
   int log_and_order(THD *thd, my_xid xid, bool all,
                     bool need_prepare_ordered, bool need_commit_ordered);
   int unlog(ulong cookie, my_xid xid);
+  int unlog_xa_prepare(THD *thd, bool all);
   void commit_checkpoint_notify(void *cookie);
   int recover(LOG_INFO *linfo, const char *last_log_name, IO_CACHE *first_log,
               Format_description_log_event *fdle, bool do_xa);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 4c1c18fffff..ee44f7f1da4 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1178,6 +1178,9 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
     case XID_EVENT:
       ev = new Xid_log_event(buf, fdle);
       break;
+    case XA_PREPARE_LOG_EVENT:
+      ev = new XA_prepare_log_event(buf, fdle);
+      break;
     case RAND_EVENT:
       ev = new Rand_log_event(buf, fdle);
       break;
@@ -1229,7 +1232,6 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
     case PREVIOUS_GTIDS_LOG_EVENT:
     case TRANSACTION_CONTEXT_EVENT:
     case VIEW_CHANGE_EVENT:
-    case XA_PREPARE_LOG_EVENT:
       ev= new Ignorable_log_event(buf, fdle,
                                   get_type_str((Log_event_type) event_type));
       break;
@@ -2066,6 +2068,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
       post_header_len[USER_VAR_EVENT-1]= USER_VAR_HEADER_LEN;
       post_header_len[FORMAT_DESCRIPTION_EVENT-1]= FORMAT_DESCRIPTION_HEADER_LEN;
       post_header_len[XID_EVENT-1]= XID_HEADER_LEN;
+      post_header_len[XA_PREPARE_LOG_EVENT-1]= XA_PREPARE_HEADER_LEN;
       post_header_len[BEGIN_LOAD_QUERY_EVENT-1]= BEGIN_LOAD_QUERY_HEADER_LEN;
       post_header_len[EXECUTE_LOAD_QUERY_EVENT-1]= EXECUTE_LOAD_QUERY_HEADER_LEN;
       /*
@@ -2556,7 +2559,7 @@ Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
 
 Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
                const Format_description_log_event *description_event)
-  : Log_event(buf, description_event), seq_no(0), commit_id(0)
+  : Log_event(buf, description_event), seq_no(0), commit_id(0), xid_pins_idx(0)
 {
   uint8 header_size= description_event->common_header_len;
   uint8 post_header_len= description_event->post_header_len[GTID_EVENT-1];
@@ -2569,7 +2572,7 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
   buf+= 8;
   domain_id= uint4korr(buf);
   buf+= 4;
-  flags2= *buf;
+  flags2= *(buf++);
   if (flags2 & FL_GROUP_COMMIT_ID)
   {
     if (event_len < (uint)header_size + GTID_HEADER_LEN + 2)
@@ -2577,8 +2580,24 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
       seq_no= 0;                                // So is_valid() returns false
       return;
     }
-    ++buf;
     commit_id= uint8korr(buf);
+    buf+= 8;
+  }
+  if (flags2 & (FL_PREPARED_XA | FL_COMPLETED_XA))
+  {
+    uint32 temp= 0;
+
+    memcpy(&temp, buf, sizeof(temp));
+    xid.formatID= uint4korr(&temp);
+    buf += sizeof(temp);
+
+    xid.gtrid_length= (long) buf[0];
+    xid.bqual_length= (long) buf[1];
+    buf+= 2;
+
+    long data_length= xid.bqual_length + xid.gtrid_length;
+    memcpy(xid.data, buf, data_length);
+    buf+= data_length;
   }
 }
 
@@ -2764,7 +2783,7 @@ Rand_log_event::Rand_log_event(const char* buf,
 Xid_log_event::
 Xid_log_event(const char* buf,
               const Format_description_log_event *description_event)
-  :Log_event(buf, description_event)
+  :Xid_apply_log_event(buf, description_event)
 {
   /* The Post-Header is empty. The Variable Data part begins immediately. */
   buf+= description_event->common_header_len +
@@ -2772,6 +2791,36 @@ Xid_log_event(const char* buf,
   memcpy((char*) &xid, buf, sizeof(xid));
 }
 
+/**************************************************************************
+  XA_prepare_log_event methods
+**************************************************************************/
+XA_prepare_log_event::
+XA_prepare_log_event(const char* buf,
+                     const Format_description_log_event *description_event)
+  :Xid_apply_log_event(buf, description_event)
+{
+  uint32 temp= 0;
+  uint8 temp_byte;
+
+  buf+= description_event->common_header_len +
+    description_event->post_header_len[XA_PREPARE_LOG_EVENT-1];
+  memcpy(&temp_byte, buf, 1);
+  one_phase= (bool) temp_byte;
+  buf += sizeof(temp_byte);
+  memcpy(&temp, buf, sizeof(temp));
+  m_xid.formatID= uint4korr(&temp);
+  buf += sizeof(temp);
+  memcpy(&temp, buf, sizeof(temp));
+  m_xid.gtrid_length= uint4korr(&temp);
+  buf += sizeof(temp);
+  memcpy(&temp, buf, sizeof(temp));
+  m_xid.bqual_length= uint4korr(&temp);
+  buf += sizeof(temp);
+  memcpy(m_xid.data, buf, m_xid.gtrid_length + m_xid.bqual_length);
+
+  xid= NULL;
+}
+
 
 /**************************************************************************
   User_var_log_event methods
diff --git a/sql/log_event.h b/sql/log_event.h
index 15442bd5a97..a6543b70eb5 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -222,6 +222,7 @@ class String;
 #define GTID_HEADER_LEN       19
 #define GTID_LIST_HEADER_LEN   4
 #define START_ENCRYPTION_HEADER_LEN 0
+#define XA_PREPARE_HEADER_LEN 0
 
 /* 
   Max number of possible extra bytes in a replication event compared to a
@@ -664,6 +665,7 @@ enum Log_event_type
   /* MySQL 5.7 events, ignored by MariaDB */
   TRANSACTION_CONTEXT_EVENT= 36,
   VIEW_CHANGE_EVENT= 37,
+  /* not ignored */
   XA_PREPARE_LOG_EVENT= 38,
 
   /*
@@ -3022,6 +3024,32 @@ class Rand_log_event: public Log_event
 #endif
 };
 
+
+class Xid_apply_log_event: public Log_event
+{
+public:
+#ifdef MYSQL_SERVER
+  Xid_apply_log_event(THD* thd_arg):
+   Log_event(thd_arg, 0, TRUE) {}
+#endif
+  Xid_apply_log_event(const char* buf,
+                const Format_description_log_event *description_event):
+    Log_event(buf, description_event) {}
+
+  ~Xid_apply_log_event() {}
+  bool is_valid() const { return 1; }
+private:
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+  virtual int do_commit()= 0;
+  virtual int do_apply_event(rpl_group_info *rgi);
+  int do_record_gtid(THD *thd, rpl_group_info *rgi, bool in_trans,
+                     void **out_hton);
+  enum_skip_reason do_shall_skip(rpl_group_info *rgi);
+  virtual const char* get_query()= 0;
+#endif
+};
+
+
 /**
   @class Xid_log_event
 
@@ -3034,18 +3062,22 @@ class Rand_log_event: public Log_event
 typedef ulonglong my_xid; // this line is the same as in handler.h
 #endif
 
-class Xid_log_event: public Log_event
+class Xid_log_event: public Xid_apply_log_event
 {
- public:
-   my_xid xid;
+public:
+  my_xid xid;
 
 #ifdef MYSQL_SERVER
   Xid_log_event(THD* thd_arg, my_xid x, bool direct):
-   Log_event(thd_arg, 0, TRUE), xid(x)
+   Xid_apply_log_event(thd_arg), xid(x)
    {
      if (direct)
        cache_type= Log_event::EVENT_NO_CACHE;
    }
+  const char* get_query()
+  {
+    return "COMMIT /* implicit, from Xid_log_event */";
+  }
 #ifdef HAVE_REPLICATION
   void pack_info(Protocol* protocol);
 #endif /* HAVE_REPLICATION */
@@ -3061,15 +3093,171 @@ class Xid_log_event: public Log_event
 #ifdef MYSQL_SERVER
   bool write();
 #endif
-  bool is_valid() const { return 1; }
 
 private:
 #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-  virtual int do_apply_event(rpl_group_info *rgi);
-  enum_skip_reason do_shall_skip(rpl_group_info *rgi);
+  int do_commit();
 #endif
 };
 
+
+/**
+  @class XA_prepare_log_event
+
+  Similar to Xid_log_event except that
+  - it is specific to XA transaction
+  - it carries out the prepare logics rather than the final committing
+    when @c one_phase member is off. The latter option is only for
+    compatibility with the upstream.
+
+  From the groupping perspective the event finalizes the current
+  "prepare" group that is started with Gtid_log_event similarly to the
+  regular replicated transaction.
+*/
+
+/**
+  Function serializes XID which is characterized by by four last arguments
+  of the function.
+  Serialized XID is presented in valid hex format and is returned to
+  the caller in a buffer pointed by the first argument.
+  The buffer size provived by the caller must be not less than
+  8 + 2 * XIDDATASIZE +  4 * sizeof(XID::formatID) + 1, see
+  {MYSQL_,}XID definitions.
+
+  @param buf  pointer to a buffer allocated for storing serialized data
+  @param fmt  formatID value
+  @param gln  gtrid_length value
+  @param bln  bqual_length value
+  @param dat  data value
+
+  @return  the value of the buffer pointer
+*/
+
+inline char *serialize_xid(char *buf, long fmt, long gln, long bln,
+                           const char *dat)
+{
+  int i;
+  char *c= buf;
+  /*
+    Build a string consisting of the hex format representation of XID
+    as passed through fmt,gln,bln,dat argument:
+      X'hex11hex12...hex1m',X'hex21hex22...hex2n',11
+    and store it into buf.
+  */
+  c[0]= 'X';
+  c[1]= '\'';
+  c+= 2;
+  for (i= 0; i < gln; i++)
+  {
+    c[0]=_dig_vec_lower[((uchar*) dat)[i] >> 4];
+    c[1]=_dig_vec_lower[((uchar*) dat)[i] & 0x0f];
+    c+= 2;
+  }
+  c[0]= '\'';
+  c[1]= ',';
+  c[2]= 'X';
+  c[3]= '\'';
+  c+= 4;
+
+  for (; i < gln + bln; i++)
+  {
+    c[0]=_dig_vec_lower[((uchar*) dat)[i] >> 4];
+    c[1]=_dig_vec_lower[((uchar*) dat)[i] & 0x0f];
+    c+= 2;
+  }
+  c[0]= '\'';
+  sprintf(c+1, ",%lu", fmt);
+
+ return buf;
+}
+
+/*
+  The size of the string containing serialized Xid representation
+  is computed as a sum of
+  eight as the number of formatting symbols (X'',X'',)
+  plus 2 x XIDDATASIZE (2 due to hex format),
+  plus space for decimal digits of XID::formatID,
+  plus one for 0x0.
+*/
+static const uint ser_buf_size=
+  8 + 2 * MYSQL_XIDDATASIZE + 4 * sizeof(long) + 1;
+
+struct event_mysql_xid_t :  MYSQL_XID
+{
+  char buf[ser_buf_size];
+  char *serialize()
+  {
+    return serialize_xid(buf, formatID, gtrid_length, bqual_length, data);
+  }
+};
+
+#ifndef MYSQL_CLIENT
+struct event_xid_t : XID
+{
+  char buf[ser_buf_size];
+
+  char *serialize(char *buf_arg)
+  {
+    return serialize_xid(buf_arg, formatID, gtrid_length, bqual_length, data);
+  }
+  char *serialize()
+  {
+    return serialize(buf);
+  }
+};
+#endif
+
+class XA_prepare_log_event: public Xid_apply_log_event
+{
+protected:
+
+  /* Constant contributor to subheader in write() by members of XID struct. */
+  static const int xid_subheader_no_data= 12;
+  event_mysql_xid_t m_xid;
+  void *xid;
+  bool one_phase;
+
+public:
+#ifdef MYSQL_SERVER
+  XA_prepare_log_event(THD* thd_arg, XID *xid_arg, bool one_phase_arg):
+    Xid_apply_log_event(thd_arg), xid(xid_arg), one_phase(one_phase_arg)
+  {
+    cache_type= Log_event::EVENT_NO_CACHE;
+  }
+#ifdef HAVE_REPLICATION
+  void pack_info(Protocol* protocol);
+#endif /* HAVE_REPLICATION */
+#else
+  bool print(FILE* file, PRINT_EVENT_INFO* print_event_info);
+#endif
+  XA_prepare_log_event(const char* buf,
+                       const Format_description_log_event *description_event);
+  ~XA_prepare_log_event() {}
+  Log_event_type get_type_code() { return XA_PREPARE_LOG_EVENT; }
+  int get_data_size()
+  {
+    return xid_subheader_no_data + m_xid.gtrid_length + m_xid.bqual_length;
+  }
+
+#ifdef MYSQL_SERVER
+  bool write();
+#endif
+
+private:
+#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
+  char query[sizeof("XA COMMIT ONE PHASE") + 1 + ser_buf_size];
+  int do_commit();
+  const char* get_query()
+  {
+    sprintf(query,
+            (one_phase ? "XA COMMIT %s ONE PHASE" : "XA PREPARE %s"),
+            m_xid.serialize());
+    return query;
+  }
+#endif
+};
+
+
 /**
   @class User_var_log_event
 
@@ -3382,8 +3570,13 @@ class Gtid_log_event: public Log_event
   uint64 seq_no;
   uint64 commit_id;
   uint32 domain_id;
+#ifdef MYSQL_SERVER
+  event_xid_t xid;
+#else
+  event_mysql_xid_t xid;
+#endif
   uchar flags2;
-
+  uint32 xid_pins_idx;
   /* Flags2. */
 
   /* FL_STANDALONE is set when there is no terminating COMMIT event. */
@@ -3410,6 +3603,10 @@ class Gtid_log_event: public Log_event
   static const uchar FL_WAITED= 16;
   /* FL_DDL is set for event group containing DDL. */
   static const uchar FL_DDL= 32;
+  /* FL_PREPARED_XA is set for XA transaction. */
+  static const uchar FL_PREPARED_XA= 64;
+  /* FL_"COMMITTED or ROLLED-BACK"_XA is set for XA transaction. */
+  static const uchar FL_COMPLETED_XA= 128;
 
 #ifdef MYSQL_SERVER
   Gtid_log_event(THD *thd_arg, uint64 seq_no, uint32 domain_id, bool standalone,
diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc
index cae4842355a..0e57b82476b 100644
--- a/sql/log_event_client.cc
+++ b/sql/log_event_client.cc
@@ -3892,11 +3892,44 @@ Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
                       buf, print_event_info->delimiter))
         goto err;
   }
-  if (!(flags2 & FL_STANDALONE))
-    if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", print_event_info->delimiter))
+  if ((flags2 & FL_PREPARED_XA) && !is_flashback)
+  {
+    my_b_write_string(&cache, "XA START ");
+    xid.serialize();
+    my_b_write(&cache, (uchar*) xid.buf, strlen(xid.buf));
+    if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
+      goto err;
+  }
+  else if (!(flags2 & FL_STANDALONE))
+  {
+    if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n",
+                    print_event_info->delimiter))
       goto err;
+  }
 
   return cache.flush_data();
 err:
   return 1;
 }
+
+bool XA_prepare_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+  Write_on_release_cache cache(&print_event_info->head_cache, file,
+                               Write_on_release_cache::FLUSH_F, this);
+  m_xid.serialize();
+
+  if (!print_event_info->short_form)
+  {
+    print_header(&cache, print_event_info, FALSE);
+    if (my_b_printf(&cache, "\tXID = %s\n", m_xid.buf))
+      goto error;
+  }
+
+  if (my_b_printf(&cache, "XA PREPARE %s\n%s\n",
+                   m_xid.buf, print_event_info->delimiter))
+    goto error;
+
+  return cache.flush_data();
+error:
+  return TRUE;
+}
diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc
index 202a41c2837..210d321d2cd 100644
--- a/sql/log_event_server.cc
+++ b/sql/log_event_server.cc
@@ -1487,6 +1487,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, size_t que
       case SQLCOM_RELEASE_SAVEPOINT:
       case SQLCOM_ROLLBACK_TO_SAVEPOINT:
       case SQLCOM_SAVEPOINT:
+      case SQLCOM_XA_END:
         use_cache= trx_cache= TRUE;
         break;
       default:
@@ -3218,6 +3219,26 @@ Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
   /* Preserve any DDL or WAITED flag in the slave's binlog. */
   if (thd_arg->rgi_slave)
     flags2|= (thd_arg->rgi_slave->gtid_ev_flags2 & (FL_DDL|FL_WAITED));
+
+  XID_STATE &xid_state= thd->transaction.xid_state;
+  if (is_transactional && xid_state.is_explicit_XA() &&
+      ((xid_state.get_state_code() == XA_IDLE &&
+        thd->lex->sql_command == SQLCOM_XA_PREPARE) ||
+       xid_state.get_state_code() == XA_PREPARED))
+  {
+    DBUG_ASSERT(thd->lex->xa_opt != XA_ONE_PHASE);
+    DBUG_ASSERT(xid_state.get_state_code() == XA_IDLE ||
+                xid_state.is_binlogged());
+
+    flags2|= xid_state.get_state_code() == XA_IDLE ?
+      FL_PREPARED_XA : FL_COMPLETED_XA;
+
+    xid.formatID=     xid_state.get_xid()->formatID;
+    xid.gtrid_length= xid_state.get_xid()->gtrid_length;
+    xid.bqual_length= xid_state.get_xid()->bqual_length;
+    long data_length= xid.bqual_length + xid.gtrid_length;
+    memcpy(xid.data, xid_state.get_xid()->data, data_length);
+  }
 }
 
 
@@ -3260,7 +3281,7 @@ Gtid_log_event::peek(const char *event_start, size_t event_len,
 bool
 Gtid_log_event::write()
 {
-  uchar buf[GTID_HEADER_LEN+2];
+  uchar buf[GTID_HEADER_LEN+2+sizeof(XID)];
   size_t write_len;
 
   int8store(buf, seq_no);
@@ -3272,8 +3293,22 @@ Gtid_log_event::write()
     write_len= GTID_HEADER_LEN + 2;
   }
   else
+    write_len= 13;
+
+  if (flags2 & (FL_PREPARED_XA | FL_COMPLETED_XA))
+  {
+    int4store(&buf[write_len],   xid.formatID);
+    buf[write_len +4]=   (uchar) xid.gtrid_length;
+    buf[write_len +4+1]= (uchar) xid.bqual_length;
+    write_len+= 6;
+    long data_length= xid.bqual_length + xid.gtrid_length;
+    memcpy(buf+write_len, xid.data, data_length);
+    write_len+= data_length;
+  }
+
+  if (write_len < GTID_HEADER_LEN)
   {
-    bzero(buf+13, GTID_HEADER_LEN-13);
+    bzero(buf+write_len, GTID_HEADER_LEN-write_len);
     write_len= GTID_HEADER_LEN;
   }
   return write_header(write_len) ||
@@ -3316,9 +3351,14 @@ Gtid_log_event::make_compatible_event(String *packet, bool *need_dummy_event,
 void
 Gtid_log_event::pack_info(Protocol *protocol)
 {
-  char buf[6+5+10+1+10+1+20+1+4+20+1];
+  char buf[6+5+10+1+10+1+20+1+4+20+1+ ser_buf_size+5 /* sprintf */];
   char *p;
-  p = strmov(buf, (flags2 & FL_STANDALONE ? "GTID " : "BEGIN GTID "));
+  p = strmov(buf, (flags2 & FL_STANDALONE  ? "GTID " :
+                   flags2 & FL_PREPARED_XA ? "XA START " : "BEGIN GTID "));
+  if (flags2 & FL_PREPARED_XA)
+  {
+    p += sprintf(p, "%s GTID ", xid.serialize());
+  }
   p= longlong10_to_str(domain_id, p, 10);
   *p++= '-';
   p= longlong10_to_str(server_id, p, 10);
@@ -3378,16 +3418,37 @@ Gtid_log_event::do_apply_event(rpl_group_info *rgi)
     bits|= (ulonglong)OPTION_RPL_SKIP_PARALLEL;
   thd->variables.option_bits= bits;
   DBUG_PRINT("info", ("Set OPTION_GTID_BEGIN"));
-  thd->set_query_and_id(gtid_begin_string, sizeof(gtid_begin_string)-1,
-                        &my_charset_bin, next_query_id());
-  thd->lex->sql_command= SQLCOM_BEGIN;
   thd->is_slave_error= 0;
-  status_var_increment(thd->status_var.com_stat[thd->lex->sql_command]);
-  if (trans_begin(thd, 0))
+
+  char buf_xa[sizeof("XA START") + 1 + ser_buf_size];
+  if (flags2 & FL_PREPARED_XA)
   {
-    DBUG_PRINT("error", ("trans_begin() failed"));
-    thd->is_slave_error= 1;
+    const char fmt[]= "XA START %s";
+
+    thd->lex->xid= &xid;
+    thd->lex->xa_opt= XA_NONE;
+    sprintf(buf_xa, fmt, xid.serialize());
+    thd->set_query_and_id(buf_xa, static_cast<uint32>(strlen(buf_xa)),
+                          &my_charset_bin, next_query_id());
+    thd->lex->sql_command= SQLCOM_XA_START;
+    if (trans_xa_start(thd))
+    {
+      DBUG_PRINT("error", ("trans_xa_start() failed"));
+      thd->is_slave_error= 1;
+    }
+  }
+  else
+  {
+    thd->set_query_and_id(gtid_begin_string, sizeof(gtid_begin_string)-1,
+                          &my_charset_bin, next_query_id());
+    thd->lex->sql_command= SQLCOM_BEGIN;
+    if (trans_begin(thd, 0))
+    {
+      DBUG_PRINT("error", ("trans_begin() failed"));
+      thd->is_slave_error= 1;
+    }
   }
+  status_var_increment(thd->status_var.com_stat[thd->lex->sql_command]);
   thd->update_stats();
 
   if (likely(!thd->is_slave_error))
@@ -3771,46 +3832,58 @@ bool slave_execute_deferred_events(THD *thd)
 
 
 /**************************************************************************
-  Xid_log_event methods
+  Xid_apply_log_event methods
 **************************************************************************/
 
 #if defined(HAVE_REPLICATION)
-void Xid_log_event::pack_info(Protocol *protocol)
+
+int Xid_apply_log_event::do_record_gtid(THD *thd, rpl_group_info *rgi,
+                                        bool in_trans, void **out_hton)
 {
-  char buf[128], *pos;
-  pos= strmov(buf, "COMMIT /* xid=");
-  pos= longlong10_to_str(xid, pos, 10);
-  pos= strmov(pos, " */");
-  protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
-}
-#endif
+  int err= 0;
+  Relay_log_info const *rli= rgi->rli;
 
+  rgi->gtid_pending= false;
+  err= rpl_global_gtid_slave_state->record_gtid(thd, &rgi->current_gtid,
+                                                rgi->gtid_sub_id,
+                                                in_trans, false, out_hton);
 
-bool Xid_log_event::write()
-{
-  DBUG_EXECUTE_IF("do_not_write_xid", return 0;);
-  return write_header(sizeof(xid)) ||
-         write_data((uchar*)&xid, sizeof(xid)) ||
-         write_footer();
-}
+  if (unlikely(err))
+  {
+    int ec= thd->get_stmt_da()->sql_errno();
+    /*
+      Do not report an error if this is really a kill due to a deadlock.
+      In this case, the transaction will be re-tried instead.
+    */
+    if (!is_parallel_retry_error(rgi, ec))
+      rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(),
+                  "Error during XID COMMIT: failed to update GTID state in "
+                  "%s.%s: %d: %s",
+                  "mysql", rpl_gtid_slave_state_table_name.str, ec,
+                  thd->get_stmt_da()->message());
+    thd->is_slave_error= 1;
+  }
 
+  return err;
+}
 
-#if defined(HAVE_REPLICATION)
-int Xid_log_event::do_apply_event(rpl_group_info *rgi)
+int Xid_apply_log_event::do_apply_event(rpl_group_info *rgi)
 {
   bool res;
   int err;
-  rpl_gtid gtid;
   uint64 sub_id= 0;
-  Relay_log_info const *rli= rgi->rli;
   void *hton= NULL;
+  rpl_gtid gtid;
 
   /*
-    XID_EVENT works like a COMMIT statement. And it also updates the
-    mysql.gtid_slave_pos table with the GTID of the current transaction.
-
+    An instance of this class such as XID_EVENT works like a COMMIT
+    statement. It updates mysql.gtid_slave_pos with the GTID of the
+    current transaction.
     Therefore, it acts much like a normal SQL statement, so we need to do
     THD::reset_for_next_command() as if starting a new statement.
+
+    XA_PREPARE_LOG_EVENT also updates the gtid table *but* the update gets
+    committed as separate "autocommit" transaction.
   */
   thd->reset_for_next_command();
   /*
@@ -3824,57 +3897,50 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
   if (rgi->gtid_pending)
   {
     sub_id= rgi->gtid_sub_id;
-    rgi->gtid_pending= false;
-
     gtid= rgi->current_gtid;
-    err= rpl_global_gtid_slave_state->record_gtid(thd, &gtid, sub_id, true,
-                                                  false, &hton);
-    if (unlikely(err))
+
+    if (!thd->transaction.xid_state.is_explicit_XA())
     {
-      int ec= thd->get_stmt_da()->sql_errno();
-      /*
-        Do not report an error if this is really a kill due to a deadlock.
-        In this case, the transaction will be re-tried instead.
-      */
-      if (!is_parallel_retry_error(rgi, ec))
-        rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(),
-                    "Error during XID COMMIT: failed to update GTID state in "
-                    "%s.%s: %d: %s",
-                    "mysql", rpl_gtid_slave_state_table_name.str, ec,
-                    thd->get_stmt_da()->message());
-      thd->is_slave_error= 1;
-      return err;
+      if ((err= do_record_gtid(thd, rgi, true /* in_trans */, &hton)))
+        return err;
+
+      DBUG_EXECUTE_IF("gtid_fail_after_record_gtid",
+                      {
+                        my_error(ER_ERROR_DURING_COMMIT, MYF(0),
+                                 HA_ERR_WRONG_COMMAND);
+                        thd->is_slave_error= 1;
+                        return 1;
+                      });
     }
-
-    DBUG_EXECUTE_IF("gtid_fail_after_record_gtid",
-        { my_error(ER_ERROR_DURING_COMMIT, MYF(0), HA_ERR_WRONG_COMMAND);
-          thd->is_slave_error= 1;
-          return 1;
-        });
   }
 
-  /* For a slave Xid_log_event is COMMIT */
-  general_log_print(thd, COM_QUERY,
-                    "COMMIT /* implicit, from Xid_log_event */");
+  general_log_print(thd, COM_QUERY, get_query());
   thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
-  res= trans_commit(thd); /* Automatically rolls back on error. */
-  thd->mdl_context.release_transactional_locks();
+  res= do_commit();
+  if (!res && rgi->gtid_pending)
+  {
+    DBUG_ASSERT(!thd->transaction.xid_state.is_explicit_XA());
 
+    if ((err= do_record_gtid(thd, rgi, false, &hton)))
+      return err;
+  }
   if (likely(!res) && sub_id)
     rpl_global_gtid_slave_state->update_state_hash(sub_id, &gtid, hton, rgi);
 
   /*
     Increment the global status commit count variable
   */
-  status_var_increment(thd->status_var.com_stat[SQLCOM_COMMIT]);
+  enum enum_sql_command cmd= !thd->transaction.xid_state.is_explicit_XA() ?
+    SQLCOM_COMMIT : SQLCOM_XA_PREPARE;
+  status_var_increment(thd->status_var.com_stat[cmd]);
 
   return res;
 }
 
 Log_event::enum_skip_reason
-Xid_log_event::do_shall_skip(rpl_group_info *rgi)
+Xid_apply_log_event::do_shall_skip(rpl_group_info *rgi)
 {
-  DBUG_ENTER("Xid_log_event::do_shall_skip");
+  DBUG_ENTER("Xid_apply_log_event::do_shall_skip");
   if (rgi->rli->slave_skip_counter > 0)
   {
     DBUG_ASSERT(!rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
@@ -3898,9 +3964,108 @@ Xid_log_event::do_shall_skip(rpl_group_info *rgi)
 #endif
   DBUG_RETURN(Log_event::do_shall_skip(rgi));
 }
+#endif /* HAVE_REPLICATION */
+
+/**************************************************************************
+  Xid_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Xid_log_event::pack_info(Protocol *protocol)
+{
+  char buf[128], *pos;
+  pos= strmov(buf, "COMMIT /* xid=");
+  pos= longlong10_to_str(xid, pos, 10);
+  pos= strmov(pos, " */");
+  protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+
+
+int Xid_log_event::do_commit()
+{
+  bool res;
+  res= trans_commit(thd); /* Automatically rolls back on error. */
+  thd->mdl_context.release_transactional_locks();
+  return res;
+}
+#endif
+
+
+bool Xid_log_event::write()
+{
+  DBUG_EXECUTE_IF("do_not_write_xid", return 0;);
+  return write_header(sizeof(xid)) ||
+         write_data((uchar*)&xid, sizeof(xid)) ||
+         write_footer();
+}
+
+/**************************************************************************
+  XA_prepare_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void XA_prepare_log_event::pack_info(Protocol *protocol)
+{
+  char query[sizeof("XA COMMIT ONE PHASE") + 1 + ser_buf_size];
+
+  sprintf(query,
+          (one_phase ? "XA COMMIT %s ONE PHASE" :  "XA PREPARE %s"),
+          m_xid.serialize());
+
+  protocol->store(query, strlen(query), &my_charset_bin);
+}
+
+
+int XA_prepare_log_event::do_commit()
+{
+  int res;
+  xid_t xid;
+  xid.set(m_xid.formatID,
+          m_xid.data, m_xid.gtrid_length,
+          m_xid.data + m_xid.gtrid_length, m_xid.bqual_length);
+
+  thd->lex->xid= &xid;
+  if (!one_phase)
+  {
+    if ((res= thd->wait_for_prior_commit()))
+      return res;
+
+    thd->lex->sql_command= SQLCOM_XA_PREPARE;
+    res= trans_xa_prepare(thd);
+  }
+  else
+  {
+    res= trans_xa_commit(thd);
+    thd->mdl_context.release_transactional_locks();
+  }
+
+  return res;
+}
 #endif // HAVE_REPLICATION
 
 
+bool XA_prepare_log_event::write()
+{
+  uchar data[1 + 4 + 4 + 4]= {one_phase,};
+  uint8 one_phase_byte= one_phase;
+
+  int4store(data+1, static_cast<XID*>(xid)->formatID);
+  int4store(data+(1+4), static_cast<XID*>(xid)->gtrid_length);
+  int4store(data+(1+4+4), static_cast<XID*>(xid)->bqual_length);
+
+  DBUG_ASSERT(xid_subheader_no_data == sizeof(data) - 1);
+
+  return write_header(sizeof(one_phase_byte) + xid_subheader_no_data +
+                      static_cast<XID*>(xid)->gtrid_length +
+                      static_cast<XID*>(xid)->bqual_length) ||
+         write_data(data, sizeof(data)) ||
+         write_data((uchar*) static_cast<XID*>(xid)->data,
+                     static_cast<XID*>(xid)->gtrid_length +
+                     static_cast<XID*>(xid)->bqual_length) ||
+         write_footer();
+}
+
+
 /**************************************************************************
   User_var_log_event methods
 **************************************************************************/
@@ -8303,7 +8468,6 @@ bool event_that_should_be_ignored(const char *buf)
       event_type == PREVIOUS_GTIDS_LOG_EVENT ||
       event_type == TRANSACTION_CONTEXT_EVENT ||
       event_type == VIEW_CHANGE_EVENT ||
-      event_type == XA_PREPARE_LOG_EVENT ||
       (uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F))
     return 1;
   return 0;
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 4313840119e..fc6475a170b 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -27,6 +27,38 @@ struct rpl_parallel_thread_pool global_rpl_thread_pool;
 static void signal_error_to_sql_driver_thread(THD *thd, rpl_group_info *rgi,
                                               int err);
 
+struct XID_cache_insert_element
+{
+  XID *xid;
+  uint32 worker_idx;
+
+  XID_cache_insert_element(XID *xid_arg, uint32 idx_arg):
+    xid(xid_arg), worker_idx(idx_arg) {}
+};
+
+class XID_cache_element_para
+{
+public:
+  XID xid;
+  uint32 worker_idx;
+  Atomic_counter<int32_t> cnt; // of consecutive namesake xa:s queued for exec
+  static void lf_hash_initializer(LF_HASH *hash __attribute__((unused)),
+                                  XID_cache_element_para *element,
+                                  XID_cache_insert_element *new_element)
+  {
+    element->xid.set(new_element->xid);
+    element->worker_idx= new_element->worker_idx;
+    element->cnt= 1;
+  }
+  static uchar *key(const XID_cache_element_para *element, size_t *length,
+                    my_bool)
+  {
+    *length= element->xid.key_length();
+    return element->xid.key();
+  }
+};
+
+
 static int
 rpt_handle_event(rpl_parallel_thread::queued_event *qev,
                  struct rpl_parallel_thread *rpt)
@@ -271,6 +303,33 @@ finish_event_group(rpl_parallel_thread *rpt, uint64 sub_id,
   */
   thd->get_stmt_da()->reset_diagnostics_area();
   wfc->wakeup_subsequent_commits(rgi->worker_error);
+
+  if (!rgi->current_xid.is_null())
+  {
+    Relay_log_info *rli= rgi->rli;
+    LF_PINS *pins= rli->parallel.rpl_xid_pins[rgi->xid_pins_idx];
+
+    DBUG_ASSERT(rgi->xid_pins_idx > 0 &&
+                rgi->xid_pins_idx <= opt_slave_parallel_threads);
+
+    XID_cache_element_para* el=
+      rli->parallel.xid_cache_search(&rgi->current_xid, pins);
+
+    if (el)
+    {
+      lf_hash_search_unpin(pins); // it's safe unpin now none but us can delete
+      if (el->cnt-- == 1)         // comparison aganst old value
+        (void) rli->parallel.xid_cache_delete(el, pins);
+
+      DBUG_ASSERT(el->cnt >= 0);
+    }
+    else
+    {
+      // no record is begign when replication resumes after XA PREPARE.
+      sql_print_warning(ER_THD(rli->sql_driver_thd, ER_XAER_NOTA));
+    }
+  }
+  rgi->current_xid.null();
 }
 
 
@@ -672,12 +731,14 @@ convert_kill_to_deadlock_error(rpl_group_info *rgi)
 static int
 is_group_ending(Log_event *ev, Log_event_type event_type)
 {
-  if (event_type == XID_EVENT)
+  if (event_type == XID_EVENT || event_type == XA_PREPARE_LOG_EVENT)
     return 1;
   if (event_type == QUERY_EVENT)  // COMMIT/ROLLBACK are never compressed
   {
     Query_log_event *qev = (Query_log_event *)ev;
-    if (qev->is_commit())
+    if (qev->is_commit() ||
+        !strncmp(qev->query, STRING_WITH_LEN("XA COMMIT")) ||
+        !strncmp(qev->query, STRING_WITH_LEN("XA ROLLBACK")))
       return 1;
     if (qev->is_rollback())
       return 2;
@@ -1269,6 +1330,12 @@ handle_rpl_parallel_thread(void *arg)
           slave_output_error_info(rgi, thd);
           signal_error_to_sql_driver_thread(thd, rgi, 1);
         }
+        if (static_cast<Gtid_log_event*>(qev->ev)->
+            flags2 & Gtid_log_event::FL_COMPLETED_XA)
+        {
+          rgi->current_xid.set(&static_cast<Gtid_log_event*>(qev->ev)->xid);
+          rgi->xid_pins_idx= static_cast<Gtid_log_event*>(qev->ev)->xid_pins_idx;
+        }
       }
 
       group_rgi= rgi;
@@ -2090,24 +2157,71 @@ rpl_parallel_thread_pool::release_thread(rpl_parallel_thread *rpt)
 
   If the flag `reuse' is set, the last worker thread will be returned again,
   if it is still available. Otherwise a new worker thread is allocated.
+
+  XA flagged as COMPLETED or PREPARED are handled as the following.
+
+  For the PREPARED one, a record consisting of the xid and a choosen worker's
+  descriptor is inserted into a local rli parallel xid hash.
+  The record also contains a usage counter field to account for
+  "duplicate" xid:s which may arise naturally as the result of the
+  same xid transaction multiple times execution on master. Each emerging
+  PREPARED xa increments the usage counter of the record keyed by xid.
+
+  For the COMPLETED xa, its xid is searched in the local hash for the
+  xa prepared worker.  A found record's worker is reused, and when not
+  found (which may be benign) a new worker is allocated by the regular rule.
+
+  While the driver thread is responsible to insert a xid record into
+  the local hash and possibly increment its usage counter, a Worker assigned
+  for that xid decrements the counter at the end of xa's completion and deletes
+  the record when the counter drops to zero.
+  Pins associated with the Worker are passed to it through Gtid_log_event::pins
+  of the passed pointer.
 */
 rpl_parallel_thread *
 rpl_parallel_entry::choose_thread(rpl_group_info *rgi, bool *did_enter_cond,
-                                  PSI_stage_info *old_stage, bool reuse)
+                                  PSI_stage_info *old_stage,
+                                  Gtid_log_event *gtid_ev)
 {
   uint32 idx;
   Relay_log_info *rli= rgi->rli;
   rpl_parallel_thread *thr;
+  bool reuse= gtid_ev == NULL;
 
   idx= rpl_thread_idx;
+
   if (!reuse)
   {
+    if (gtid_ev->flags2 &
+        (Gtid_log_event::FL_COMPLETED_XA | Gtid_log_event::FL_PREPARED_XA))
+    {
+      LF_PINS *pins= rli->parallel.rpl_xid_pins[0];
+      XID_cache_element_para* el= rli->parallel.xid_cache_search(&gtid_ev->xid,
+                                                                 pins);
+
+      if (el)
+      {
+        idx= el->worker_idx;
+        lf_hash_search_unpin(pins);
+        goto idx_assigned;
+      }
+      else
+      {
+        // Further execution will clear out whether it's indeed the error case.
+        // XA completion event may arrive without the prepare one done so.
+        if  (gtid_ev->flags2 & Gtid_log_event::FL_COMPLETED_XA)
+          sql_print_warning(ER_THD(rli->sql_driver_thd, ER_XAER_NOTA));
+      }
+    }
     ++idx;
     if (idx >= rpl_thread_max)
       idx= 0;
+
+idx_assigned:
     rpl_thread_idx= idx;
   }
   thr= rpl_threads[idx];
+
   if (thr)
   {
     *did_enter_cond= false;
@@ -2177,6 +2291,14 @@ rpl_parallel_entry::choose_thread(rpl_group_info *rgi, bool *did_enter_cond,
     rpl_threads[idx]= thr= global_rpl_thread_pool.get_thread(&rpl_threads[idx],
                                                              this);
 
+  if (thr && gtid_ev)
+  {
+    if (gtid_ev->flags2 & Gtid_log_event::FL_PREPARED_XA)
+      (void) rli->parallel.xid_cache_replace(&gtid_ev->xid, idx);
+    else if (gtid_ev->flags2 & Gtid_log_event::FL_COMPLETED_XA)
+      gtid_ev->xid_pins_idx= idx + 1; // pass pins index to the assigned worker
+  }
+
   return thr;
 }
 
@@ -2205,12 +2327,21 @@ rpl_parallel::rpl_parallel() :
 }
 
 
-void
-rpl_parallel::reset()
+bool
+rpl_parallel::reset(bool is_parallel)
 {
   my_hash_reset(&domain_hash);
   current= NULL;
   sql_thread_stopping= false;
+  if (is_parallel)
+  {
+    xid_cache_init();
+    rpl_xid_pins= new LF_PINS*[opt_slave_parallel_threads + 1];
+    for (ulong i= 0; i <= opt_slave_parallel_threads; i++)
+      if (!(rpl_xid_pins[i]= lf_hash_get_pins(&xid_cache_para)))
+        return true;
+  }
+  return false;
 }
 
 
@@ -2473,6 +2604,76 @@ rpl_parallel::wait_for_workers_idle(THD *thd)
 }
 
 
+void rpl_parallel::xid_cache_init()
+{
+  lf_hash_init(&xid_cache_para, sizeof(XID_cache_element_para),
+               LF_HASH_UNIQUE, 0, 0,
+               (my_hash_get_key) XID_cache_element_para::key, &my_charset_bin);
+  xid_cache_para.alloc.constructor= NULL;
+  xid_cache_para.alloc.destructor= NULL;
+  xid_cache_para.initializer=
+    (lf_hash_initializer) XID_cache_element_para::lf_hash_initializer;
+}
+
+
+void rpl_parallel::xid_cache_free()
+{
+  lf_hash_destroy(&xid_cache_para);
+}
+
+
+XID_cache_element_para* rpl_parallel::xid_cache_search(XID *xid, LF_PINS* pins)
+{
+  return (XID_cache_element_para*) lf_hash_search(&xid_cache_para, pins,
+                                                  xid->key(),
+                                                  xid->key_length());
+}
+
+/**
+  Insert a first xid-keyed record, or "replace" it with incremented
+  usage counter.
+*/
+void rpl_parallel::xid_cache_replace(XID *xid, uint32 idx)
+{
+  LF_PINS *pins= rpl_xid_pins[idx + 1];
+  XID_cache_element_para* el= xid_cache_search(xid, pins);
+
+  if (el)
+  {
+    if (unlikely(el->cnt++ == 0))
+    {
+      lf_hash_search_unpin(pins);
+      while (xid_cache_search(xid, pins)) // record must be at being deleted
+        (void) LF_BACKOFF();
+      lf_hash_search_unpin(pins);
+      (void) xid_cache_insert(xid, idx);
+    }
+
+    DBUG_ASSERT(el->cnt > 0);
+  }
+  else
+  {
+    (void) xid_cache_insert(xid, idx);
+  }
+  lf_hash_search_unpin(pins);
+}
+
+bool rpl_parallel::xid_cache_insert(XID *xid, uint32 idx)
+{
+  LF_PINS *pins= rpl_xid_pins[idx + 1];
+  XID_cache_insert_element new_element(xid, idx);
+
+  return lf_hash_insert(&xid_cache_para, pins, &new_element);
+}
+
+
+bool rpl_parallel::xid_cache_delete(XID_cache_element_para* el, LF_PINS *pins)
+{
+  return lf_hash_delete(&xid_cache_para, pins,
+                        el->xid.key(), el->xid.key_length());
+}
+
+
 /*
   Handle seeing a GTID during slave restart in GTID mode. If we stopped with
   different replication domains having reached different positions in the relay
@@ -2662,7 +2863,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
       else
       {
         DBUG_ASSERT(rli->gtid_skip_flag == GTID_SKIP_TRANSACTION);
-        if (typ == XID_EVENT ||
+        if (typ == XID_EVENT || typ == XA_PREPARE_LOG_EVENT ||
             (typ == QUERY_EVENT &&  // COMMIT/ROLLBACK are never compressed
              (((Query_log_event *)ev)->is_commit() ||
               ((Query_log_event *)ev)->is_rollback())))
@@ -2673,10 +2874,11 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
     }
   }
 
+  Gtid_log_event *gtid_ev= NULL;
   if (typ == GTID_EVENT)
   {
     rpl_gtid gtid;
-    Gtid_log_event *gtid_ev= static_cast<Gtid_log_event *>(ev);
+    gtid_ev= static_cast<Gtid_log_event *>(ev);
     uint32 domain_id= (rli->mi->using_gtid == Master_info::USE_GTID_NO ||
                        rli->mi->parallel_mode <= SLAVE_PARALLEL_MINIMAL ?
                        0 : gtid_ev->domain_id);
@@ -2715,8 +2917,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
     instead re-use a thread that we queued for previously.
   */
   cur_thread=
-    e->choose_thread(serial_rgi, &did_enter_cond, &old_stage,
-                     typ != GTID_EVENT);
+    e->choose_thread(serial_rgi, &did_enter_cond, &old_stage, gtid_ev);
   if (!cur_thread)
   {
     /* This means we were killed. The error is already signalled. */
@@ -2734,7 +2935,6 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
 
   if (typ == GTID_EVENT)
   {
-    Gtid_log_event *gtid_ev= static_cast<Gtid_log_event *>(ev);
     bool new_gco;
     enum_slave_parallel_mode mode= rli->mi->parallel_mode;
     uchar gtid_flags= gtid_ev->flags2;
diff --git a/sql/rpl_parallel.h b/sql/rpl_parallel.h
index 4579d0da9bc..b27bc63255e 100644
--- a/sql/rpl_parallel.h
+++ b/sql/rpl_parallel.h
@@ -2,7 +2,7 @@
 #define RPL_PARALLEL_H
 
 #include "log_event.h"
-
+#include "lf.h"
 
 struct rpl_parallel;
 struct rpl_parallel_entry;
@@ -345,10 +345,14 @@ struct rpl_parallel_entry {
   group_commit_orderer *current_gco;
 
   rpl_parallel_thread * choose_thread(rpl_group_info *rgi, bool *did_enter_cond,
-                                      PSI_stage_info *old_stage, bool reuse);
+                                      PSI_stage_info *old_stage,
+                                      Gtid_log_event *gtid_ev);
   int queue_master_restart(rpl_group_info *rgi,
                            Format_description_log_event *fdev);
 };
+
+class XID_cache_element_para;
+
 struct rpl_parallel {
   HASH domain_hash;
   rpl_parallel_entry *current;
@@ -356,13 +360,31 @@ struct rpl_parallel {
 
   rpl_parallel();
   ~rpl_parallel();
-  void reset();
+  bool reset(bool is_parallel);
   rpl_parallel_entry *find(uint32 domain_id);
   void wait_for_done(THD *thd, Relay_log_info *rli);
   void stop_during_until();
   bool workers_idle();
   int wait_for_workers_idle(THD *thd);
   int do_event(rpl_group_info *serial_rgi, Log_event *ev, ulonglong event_size);
+  void leave(THD *thd, Relay_log_info *rli)
+  {
+    wait_for_done(thd, rli);
+    for (ulong i= 0; i <= opt_slave_parallel_threads; i++)
+      lf_hash_put_pins(rpl_xid_pins[i]);
+    delete[] rpl_xid_pins;
+    xid_cache_free();
+  };
+  // XA related. API follows xa.h naming.
+  LF_HASH xid_cache_para;
+  LF_PINS **rpl_xid_pins;
+
+  void xid_cache_init();
+  void xid_cache_free();
+  bool xid_cache_insert(XID *xid, uint32 idx);
+  void xid_cache_replace(XID *xid, uint32 idx);
+  bool xid_cache_delete(XID_cache_element_para *el, LF_PINS *pins);
+  XID_cache_element_para *xid_cache_search(XID *xid, LF_PINS *pins);
 };
 
 
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 6d55b06b497..ab035afb276 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -35,7 +35,7 @@
 #include "sql_table.h"
 
 static int count_relay_log_space(Relay_log_info* rli);
-
+bool xa_trans_force_rollback(THD *thd);
 /**
    Current replication state (hash of last GTID executed, per replication
    domain).
@@ -2103,13 +2103,15 @@ rpl_group_info::reinit(Relay_log_info *rli)
 rpl_group_info::rpl_group_info(Relay_log_info *rli)
   : thd(0), wait_commit_sub_id(0),
     wait_commit_group_info(0), parallel_entry(0),
-    deferred_events(NULL), m_annotate_event(0), is_parallel_exec(false)
+    deferred_events(NULL), m_annotate_event(0), is_parallel_exec(false),
+    xid_pins_idx(0)
 {
   reinit(rli);
   bzero(&current_gtid, sizeof(current_gtid));
   mysql_mutex_init(key_rpl_group_info_sleep_lock, &sleep_lock,
                    MY_MUTEX_INIT_FAST);
   mysql_cond_init(key_rpl_group_info_sleep_cond, &sleep_cond, NULL);
+  current_xid.null();
 }
 
 
@@ -2230,6 +2232,14 @@ void rpl_group_info::cleanup_context(THD *thd, bool error)
 
   if (unlikely(error))
   {
+    /*Todo/fixme: does it still not hold? Sort out and optimize if does not.
+      trans_rollback above does not rollback XA transactions.
+      It could be done only after necessarily closing tables which dictates
+      the following placement.
+    */
+    if (thd->transaction.xid_state.is_explicit_XA())
+      xa_trans_force_rollback(thd);
+
     thd->mdl_context.release_transactional_locks();
 
     if (thd == rli->sql_driver_thd)
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 0e2e42fcb08..0b7d7f6a377 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -808,6 +808,10 @@ struct rpl_group_info
   };
   uchar killed_for_retry;
 
+  /* A store to remember xid of being completed XA */
+  XID current_xid;
+  uint32 xid_pins_idx;  /* xid pins index to use by XA competing worker */
+
   rpl_group_info(Relay_log_info *rli_);
   ~rpl_group_info();
   void reinit(Relay_log_info *rli);
diff --git a/sql/slave.cc b/sql/slave.cc
index 87c1cf6cb77..4b3ad57fe41 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -4230,7 +4230,7 @@ inline void update_state_of_relay_log(Relay_log_info *rli, Log_event *ev)
         rli->clear_flag(Relay_log_info::IN_TRANSACTION);
     }
   }
-  if (typ == XID_EVENT)
+  if (typ == XID_EVENT || typ == XA_PREPARE_LOG_EVENT)
     rli->clear_flag(Relay_log_info::IN_TRANSACTION);
   if (typ == GTID_EVENT &&
       !(((Gtid_log_event*) ev)->flags2 & Gtid_log_event::FL_STANDALONE))
@@ -5434,7 +5434,6 @@ pthread_handler_t handle_slave_sql(void *arg)
     But the master timestamp is reset by RESET SLAVE & CHANGE MASTER.
   */
   rli->clear_error();
-  rli->parallel.reset();
 
   //tell the I/O thread to take relay_log_space_limit into account from now on
   rli->ignore_log_space_limit= 0;
@@ -5601,7 +5600,9 @@ pthread_handler_t handle_slave_sql(void *arg)
   }
 #endif /* WITH_WSREP */
   /* Read queries from the IO/THREAD until this thread is killed */
-
+  if (rli->parallel.reset(mi->using_parallel()))
+    rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL,
+                "Error initializing parallel mode");
   thd->set_command(COM_SLAVE_SQL);
   while (!sql_slave_killed(serial_rgi))
   {
@@ -5663,7 +5664,7 @@ pthread_handler_t handle_slave_sql(void *arg)
 
  err:
   if (mi->using_parallel())
-    rli->parallel.wait_for_done(thd, rli);
+    rli->parallel.leave(thd, rli);
 
   /* Thread stopped. Print the current replication position to the log */
   {
@@ -7095,6 +7096,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
                                       buf[EVENT_TYPE_OFFSET])) ||
         (!mi->last_queued_gtid_standalone &&
          ((uchar)buf[EVENT_TYPE_OFFSET] == XID_EVENT ||
+          (uchar)buf[EVENT_TYPE_OFFSET] == XA_PREPARE_LOG_EVENT ||
           ((uchar)buf[EVENT_TYPE_OFFSET] == QUERY_EVENT &&    /* QUERY_COMPRESSED_EVENT would never be commmit or rollback */
            Query_log_event::peek_is_commit_rollback(buf, event_len,
                                                     checksum_alg))))))
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 5bfa29b72c4..fd7fa89f227 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1651,7 +1651,7 @@ is_until_reached(binlog_send_info *info, ulong *ev_offset,
       return false;
     break;
   case GTID_UNTIL_STOP_AFTER_TRANSACTION:
-    if (event_type != XID_EVENT &&
+    if (event_type != XID_EVENT && event_type != XA_PREPARE_LOG_EVENT &&
         (event_type != QUERY_EVENT ||    /* QUERY_COMPRESSED_EVENT would never be commmit or rollback */
          !Query_log_event::peek_is_commit_rollback
                (info->packet->ptr()+*ev_offset,
@@ -1886,7 +1886,7 @@ send_event_to_slave(binlog_send_info *info, Log_event_type event_type,
       info->gtid_skip_group= GTID_SKIP_NOT;
     return NULL;
   case GTID_SKIP_TRANSACTION:
-    if (event_type == XID_EVENT ||
+    if (event_type == XID_EVENT || event_type == XA_PREPARE_LOG_EVENT ||
         (event_type == QUERY_EVENT && /* QUERY_COMPRESSED_EVENT would never be commmit or rollback */
          Query_log_event::peek_is_commit_rollback(packet->ptr() + ev_offset,
                                                   len - ev_offset,
diff --git a/sql/xa.cc b/sql/xa.cc
index e4cad40318e..da6c9c93157 100644
--- a/sql/xa.cc
+++ b/sql/xa.cc
@@ -20,13 +20,11 @@
 #include "sql_class.h"
 #include "transaction.h"
 
+static bool slave_applier_reset_xa_trans(THD *thd);
 
 /***************************************************************************
   Handling of XA id cacheing
 ***************************************************************************/
-enum xa_states { XA_ACTIVE= 0, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY };
-
-
 struct XID_cache_insert_element
 {
   enum xa_states xa_state;
@@ -78,6 +76,7 @@ class XID_cache_element
   uint rm_error;
   enum xa_states xa_state;
   XID xid;
+  bool binlogged;
   bool is_set(int32_t flag)
   { return m_state.load(std::memory_order_relaxed) & flag; }
   void set(int32_t flag)
@@ -131,6 +130,7 @@ class XID_cache_element
   {
     DBUG_ASSERT(!element->is_set(ACQUIRED | RECOVERED));
     element->rm_error= 0;
+    element->binlogged= false;
     element->xa_state= new_element->xa_state;
     element->xid.set(new_element->xid);
     new_element->xid_cache_element= element;
@@ -158,6 +158,29 @@ static LF_HASH xid_cache;
 static bool xid_cache_inited;
 
 
+bool XID_STATE::is_binlogged()
+{
+  return is_explicit_XA() && xid_cache_element->binlogged;
+}
+
+
+void XID_STATE::set_binlogged()
+{
+  if (xid_cache_element)
+    xid_cache_element->binlogged= true;
+}
+
+
+void XID_STATE::unset_binlogged()
+{
+  if (xid_cache_element)
+    xid_cache_element->binlogged= false;
+}
+
+
+enum xa_states XID_STATE::get_state_code() { return xid_cache_element->xa_state; }
+
+
 bool THD::fix_xid_hash_pins()
 {
   if (!xid_hash_pins)
@@ -267,6 +290,7 @@ bool xid_cache_insert(XID *xid)
   {
   case 0:
     new_element.xid_cache_element->set(XID_cache_element::RECOVERED);
+    new_element.xid_cache_element->binlogged= true;
     break;
   case 1:
     res= 0;
@@ -308,7 +332,11 @@ static void xid_cache_delete(THD *thd, XID_cache_element *&element)
 
 void xid_cache_delete(THD *thd, XID_STATE *xid_state)
 {
-  DBUG_ASSERT(xid_state->is_explicit_XA());
+  DBUG_ASSERT(xid_state->is_explicit_XA() || thd->lex->xa_opt == XA_ONE_PHASE);
+
+  if (!xid_state->is_explicit_XA())
+    return;
+
   xid_cache_delete(thd, xid_state->xid_cache_element);
   xid_state->xid_cache_element= 0;
 }
@@ -380,7 +408,7 @@ static bool xa_trans_rolled_back(XID_cache_element *element)
   @return TRUE if the rollback failed, FALSE otherwise.
 */
 
-static bool xa_trans_force_rollback(THD *thd)
+bool xa_trans_force_rollback(THD *thd)
 {
   bool rc= false;
 
@@ -389,8 +417,8 @@ static bool xa_trans_force_rollback(THD *thd)
     my_error(ER_XAER_RMERR, MYF(0));
     rc= true;
   }
-
-  thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+  thd->variables.option_bits&=
+    ~(OPTION_BEGIN | OPTION_KEEP_LOG | OPTION_GTID_BEGIN);
   thd->transaction.all.reset();
   thd->server_status&=
     ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
@@ -492,6 +520,8 @@ bool trans_xa_end(THD *thd)
 
 bool trans_xa_prepare(THD *thd)
 {
+  int res= 1;
+
   DBUG_ENTER("trans_xa_prepare");
 
   if (!thd->transaction.xid_state.is_explicit_XA() ||
@@ -499,16 +529,40 @@ bool trans_xa_prepare(THD *thd)
     thd->transaction.xid_state.er_xaer_rmfail();
   else if (!thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
     my_error(ER_XAER_NOTA, MYF(0));
-  else if (ha_prepare(thd))
+  else
   {
-    xid_cache_delete(thd, &thd->transaction.xid_state);
-    my_error(ER_XA_RBROLLBACK, MYF(0));
+    /*
+      Acquire metadata lock which will ensure that COMMIT is blocked
+      by active FLUSH TABLES WITH READ LOCK (and vice versa COMMIT in
+      progress blocks FTWRL).
+
+      We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
+    */
+    MDL_request mdl_request;
+    mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+                     MDL_STATEMENT);
+    if (thd->mdl_context.acquire_lock(&mdl_request,
+                                      thd->variables.lock_wait_timeout) ||
+        ha_prepare(thd))
+    {
+      if (!mdl_request.ticket)
+        ha_rollback_trans(thd, TRUE);
+      thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+      thd->transaction.all.reset();
+      thd->server_status&=
+        ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+      xid_cache_delete(thd, &thd->transaction.xid_state);
+      my_error(ER_XA_RBROLLBACK, MYF(0));
+    }
+    else
+    {
+      thd->transaction.xid_state.xid_cache_element->xa_state= XA_PREPARED;
+      res= thd->variables.pseudo_slave_mode || thd->slave_thread ?
+        slave_applier_reset_xa_trans(thd) : 0;
+    }
   }
-  else
-    thd->transaction.xid_state.xid_cache_element->xa_state= XA_PREPARED;
 
-  DBUG_RETURN(thd->is_error() ||
-    thd->transaction.xid_state.xid_cache_element->xa_state != XA_PREPARED);
+  DBUG_RETURN(res);
 }
 
 
@@ -523,11 +577,13 @@ bool trans_xa_prepare(THD *thd)
 
 bool trans_xa_commit(THD *thd)
 {
-  bool res= TRUE;
+  bool res= true;
+  XID_STATE &xid_state= thd->transaction.xid_state;
+
   DBUG_ENTER("trans_xa_commit");
 
-  if (!thd->transaction.xid_state.is_explicit_XA() ||
-      !thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
+  if (!xid_state.is_explicit_XA() ||
+      !xid_state.xid_cache_element->xid.eq(thd->lex->xid))
   {
     if (thd->in_multi_stmt_transaction_mode() || thd->lex->xa_opt != XA_NONE)
     {
@@ -543,7 +599,45 @@ bool trans_xa_commit(THD *thd)
     if (auto xs= xid_cache_search(thd, thd->lex->xid))
     {
       res= xa_trans_rolled_back(xs);
+      /*
+        Acquire metadata lock which will ensure that COMMIT is blocked
+        by active FLUSH TABLES WITH READ LOCK (and vice versa COMMIT in
+        progress blocks FTWRL).
+
+        We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
+      */
+      MDL_request mdl_request;
+      mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+                       MDL_STATEMENT);
+      if (thd->mdl_context.acquire_lock(&mdl_request,
+                                        thd->variables.lock_wait_timeout))
+      {
+        /*
+          We can't rollback an XA transaction on lock failure due to
+          Innodb redo log and bin log update is involved in rollback.
+          Return error to user for a retry.
+        */
+        DBUG_ASSERT(thd->is_error());
+
+        xs->acquired_to_recovered();
+        DBUG_RETURN(true);
+      }
+      DBUG_ASSERT(!xid_state.xid_cache_element);
+
+      DEBUG_SYNC(thd, "at_trans_xa_commit");
+      if (thd->wait_for_prior_commit())
+      {
+        DBUG_ASSERT(thd->is_error());
+
+        xs->acquired_to_recovered();
+        DBUG_RETURN(true);
+      }
+
+      xid_state.xid_cache_element= xs;
       ha_commit_or_rollback_by_xid(thd->lex->xid, !res);
+      xid_state.xid_cache_element= 0;
+
+      res= res || thd->is_error();
       xid_cache_delete(thd, xs);
     }
     else
@@ -551,19 +645,20 @@ bool trans_xa_commit(THD *thd)
     DBUG_RETURN(res);
   }
 
-  if (xa_trans_rolled_back(thd->transaction.xid_state.xid_cache_element))
+  if (xa_trans_rolled_back(xid_state.xid_cache_element))
   {
     xa_trans_force_rollback(thd);
     DBUG_RETURN(thd->is_error());
   }
-  else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_IDLE &&
+  else if (xid_state.xid_cache_element->xa_state == XA_IDLE &&
            thd->lex->xa_opt == XA_ONE_PHASE)
   {
+    xid_cache_delete(thd, &xid_state);
     int r= ha_commit_trans(thd, TRUE);
     if ((res= MY_TEST(r)))
       my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
   }
-  else if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_PREPARED &&
+  else if (xid_state.xid_cache_element->xa_state == XA_PREPARED &&
            thd->lex->xa_opt == XA_NONE)
   {
     MDL_request mdl_request;
@@ -576,26 +671,30 @@ bool trans_xa_commit(THD *thd)
       We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
     */
     mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
-                     MDL_TRANSACTION);
+                     MDL_STATEMENT);
 
     if (thd->mdl_context.acquire_lock(&mdl_request,
                                       thd->variables.lock_wait_timeout))
     {
-      ha_rollback_trans(thd, TRUE);
+      /*
+        We can't rollback an XA transaction on lock failure due to
+        Innodb redo log and bin log update is involved in rollback.
+        Return error to user for a retry.
+      */
       my_error(ER_XAER_RMERR, MYF(0));
+      DBUG_RETURN(true);
     }
     else
     {
       DEBUG_SYNC(thd, "trans_xa_commit_after_acquire_commit_lock");
 
-      res= MY_TEST(ha_commit_one_phase(thd, 1));
-      if (res)
+      if ((res= MY_TEST(ha_commit_one_phase(thd, 1))))
         my_error(ER_XAER_RMERR, MYF(0));
     }
   }
   else
   {
-    thd->transaction.xid_state.er_xaer_rmfail();
+    xid_state.er_xaer_rmfail();
     DBUG_RETURN(TRUE);
   }
 
@@ -604,7 +703,7 @@ bool trans_xa_commit(THD *thd)
   thd->server_status&=
     ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
   DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
-  xid_cache_delete(thd, &thd->transaction.xid_state);
+  xid_cache_delete(thd, &xid_state);
 
   trans_track_end_trx(thd);
 
@@ -623,10 +722,13 @@ bool trans_xa_commit(THD *thd)
 
 bool trans_xa_rollback(THD *thd)
 {
+  bool res= false;
+  XID_STATE &xid_state= thd->transaction.xid_state;
+
   DBUG_ENTER("trans_xa_rollback");
 
-  if (!thd->transaction.xid_state.is_explicit_XA() ||
-      !thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
+  if (!xid_state.is_explicit_XA() ||
+      !xid_state.xid_cache_element->xid.eq(thd->lex->xid))
   {
     if (thd->in_multi_stmt_transaction_mode())
     {
@@ -641,8 +743,36 @@ bool trans_xa_rollback(THD *thd)
 
     if (auto xs= xid_cache_search(thd, thd->lex->xid))
     {
+      MDL_request mdl_request;
+      mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+                       MDL_STATEMENT);
+      if (thd->mdl_context.acquire_lock(&mdl_request,
+                                        thd->variables.lock_wait_timeout))
+      {
+        /*
+          We can't rollback an XA transaction on lock failure due to
+          Innodb redo log and bin log update is involved in rollback.
+          Return error to user for a retry.
+        */
+        DBUG_ASSERT(thd->is_error());
+
+        xs->acquired_to_recovered();
+        DBUG_RETURN(true);
+      }
       xa_trans_rolled_back(xs);
+      DBUG_ASSERT(!xid_state.xid_cache_element);
+
+      DEBUG_SYNC(thd, "at_trans_xa_rollback");
+      if (thd->wait_for_prior_commit())
+      {
+        DBUG_ASSERT(thd->is_error());
+        xs->acquired_to_recovered();
+        DBUG_RETURN(true);
+      }
+
+      xid_state.xid_cache_element= xs;
       ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
+      xid_state.xid_cache_element= 0;
       xid_cache_delete(thd, xs);
     }
     else
@@ -650,21 +780,35 @@ bool trans_xa_rollback(THD *thd)
     DBUG_RETURN(thd->get_stmt_da()->is_error());
   }
 
-  if (thd->transaction.xid_state.xid_cache_element->xa_state == XA_ACTIVE)
+  if (xid_state.xid_cache_element->xa_state == XA_ACTIVE)
   {
-    thd->transaction.xid_state.er_xaer_rmfail();
+    xid_state.er_xaer_rmfail();
     DBUG_RETURN(TRUE);
   }
-  DBUG_RETURN(xa_trans_force_rollback(thd));
+
+  MDL_request mdl_request;
+  mdl_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
+      MDL_STATEMENT);
+  if (thd->mdl_context.acquire_lock(&mdl_request,
+        thd->variables.lock_wait_timeout))
+  {
+    /*
+      We can't rollback an XA transaction on lock failure due to
+      Innodb redo log and bin log update is involved in rollback.
+      Return error to user for a retry.
+    */
+    my_error(ER_XAER_RMERR, MYF(0));
+    DBUG_RETURN(true);
+  }
+
+  DBUG_RETURN(res != 0 || xa_trans_force_rollback(thd));
 }
 
 
 bool trans_xa_detach(THD *thd)
 {
   DBUG_ASSERT(thd->transaction.xid_state.is_explicit_XA());
-#if 1
-  return xa_trans_force_rollback(thd);
-#else
+
   if (thd->transaction.xid_state.xid_cache_element->xa_state != XA_PREPARED)
     return xa_trans_force_rollback(thd);
   thd->transaction.xid_state.xid_cache_element->acquired_to_recovered();
@@ -683,7 +827,6 @@ bool trans_xa_detach(THD *thd)
   thd->transaction.all.ha_list= 0;
   thd->transaction.all.no_2pc= 0;
   return false;
-#endif
 }
 
 
@@ -877,3 +1020,44 @@ bool mysql_xa_recover(THD *thd)
   my_eof(thd);
   DBUG_RETURN(0);
 }
+
+
+/**
+  This is a specific to (pseudo-) slave applier collection of standard cleanup
+  actions to reset XA transaction state sim to @c ha_commit_one_phase.
+  THD of the slave applier is dissociated from a transaction object in engine
+  that continues to exist there.
+
+  @param  THD current thread
+  @return the value of is_error()
+*/
+
+static bool slave_applier_reset_xa_trans(THD *thd)
+{
+  thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+  thd->server_status&=
+    ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
+  DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
+
+  thd->transaction.xid_state.xid_cache_element->acquired_to_recovered();
+  thd->transaction.xid_state.xid_cache_element= 0;
+
+  for (Ha_trx_info *ha_info= thd->transaction.all.ha_list, *ha_info_next;
+       ha_info; ha_info= ha_info_next)
+  {
+    ha_info_next= ha_info->next();
+    ha_info->reset();
+  }
+  thd->transaction.all.ha_list= 0;
+
+  ha_close_connection(thd);
+  thd->transaction.cleanup();
+  thd->transaction.all.reset();
+
+  DBUG_ASSERT(!thd->transaction.all.ha_list);
+  DBUG_ASSERT(!thd->transaction.all.no_2pc);
+
+  thd->has_waiter= false;
+
+  return thd->is_error();
+}
diff --git a/sql/xa.h b/sql/xa.h
index 7cf74efad35..507d07f638f 100644
--- a/sql/xa.h
+++ b/sql/xa.h
@@ -1,3 +1,5 @@
+#ifndef XA_INCLUDED
+#define XA_INCLUDED
 /*
    Copyright (c) 2000, 2016, Oracle and/or its affiliates.
    Copyright (c) 2009, 2019, MariaDB Corporation.
@@ -16,17 +18,31 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */
 
-
 class XID_cache_element;
+enum xa_states { XA_ACTIVE= 0, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY };
 
 struct XID_STATE {
   XID_cache_element *xid_cache_element;
 
-  bool check_has_uncommitted_xa() const;
   bool is_explicit_XA() const { return xid_cache_element != 0; }
+  /*
+    Binary logging status of explicit "user" XA.
+    It is set to TRUE at XA PREPARE if the transaction was written
+    to the binlog.
+    It may be FALSE after preparing when the transaction does not modify
+    transactional tables or binlogging is turned off.
+    In that case a consequent XA COMMIT/ROLLBACK shouldn't be binlogged.
+
+    The recovered transaction after server restart sets it to TRUE always.
+  */
+  bool is_binlogged();
+  bool check_has_uncommitted_xa() const;
   void set_error(uint error);
   void er_xaer_rmfail() const;
   XID *get_xid() const;
+  void set_binlogged();
+  void unset_binlogged();
+  enum xa_states get_state_code();
 };
 
 void xid_cache_init(void);
@@ -42,3 +58,5 @@ bool trans_xa_commit(THD *thd);
 bool trans_xa_rollback(THD *thd);
 bool trans_xa_detach(THD *thd);
 bool mysql_xa_recover(THD *thd);
+
+#endif /* XA_INCLUDED */
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index a36cc87a201..8a173001ed5 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -4844,6 +4844,7 @@ innobase_close_connection(
 				if (trx->has_logged_persistent()) {
 					trx_disconnect_prepared(trx);
 				} else {
+					trx_rollback_for_mysql(trx);
 					trx_deregister_from_2pc(trx);
 					goto rollback_and_free;
 				}
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index c5e48ff65ab..1004198ea0b 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -549,8 +549,10 @@ void trx_disconnect_prepared(trx_t *trx)
   trx->read_view.close();
   trx->is_recovered= true;
   trx->mysql_thd= NULL;
+  trx->mysql_log_file_name = 0;
   /* todo/fixme: suggest to do it at innodb prepare */
   trx->will_lock= 0;
+  trx_sys.rw_trx_hash.put_pins(trx);
 }
 
 /****************************************************************//**
@@ -1390,8 +1392,21 @@ trx_commit_in_memory(
 			trx->release_locks();
 		}
 
-		DEBUG_SYNC_C("after_trx_committed_in_memory");
-
+#ifndef DBUG_OFF
+                const bool debug_sync = trx->mysql_thd &&
+                                        trx->has_logged_persistent();
+		/* In case of this function is called from a stack executing
+		    THD::free_connection -> ...
+		   innobase_connection_close() ->
+		   trx_rollback_for_mysql... -> .
+		 mysql's thd does not seem to have
+		 thd->debug_sync_control defined any longer. However the stack
+		 is possible only with a prepared trx not updating any data.
+		 */
+		 if (debug_sync) {
+		   DEBUG_SYNC_C("after_trx_committed_in_memory");
+		 }
+#endif
 		if (trx->read_only || !trx->rsegs.m_redo.rseg) {
 			MONITOR_INC(MONITOR_TRX_RO_COMMIT);
 		} else {
diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc
index 8488f9ee963..272d2800319 100644
--- a/storage/rocksdb/ha_rocksdb.cc
+++ b/storage/rocksdb/ha_rocksdb.cc
@@ -3121,6 +3121,8 @@ class Rdb_transaction {
     s_tx_list.erase(this);
     RDB_MUTEX_UNLOCK_CHECK(s_tx_list_mutex);
   }
+  virtual bool is_prepared()        { return false; };
+  virtual void detach_prepared_tx() {};
 };
 
 /*
@@ -3157,7 +3159,16 @@ class Rdb_transaction_impl : public Rdb_transaction {
 
   virtual bool is_writebatch_trx() const override { return false; }
 
- private:
+  bool is_prepared() {
+    return m_rocksdb_tx && rocksdb::Transaction::PREPARED == m_rocksdb_tx->GetState();
+  }
+
+  void detach_prepared_tx() {
+    DBUG_ASSERT(rocksdb::Transaction::PREPARED == m_rocksdb_tx->GetState());
+    m_rocksdb_tx = nullptr;
+  }
+
+private:
   void release_tx(void) {
     // We are done with the current active transaction object.  Preserve it
     // for later reuse.
@@ -3798,7 +3809,8 @@ static int rocksdb_close_connection(handlerton *const hton, THD *const thd) {
           "disconnecting",
           rc);
     }
-
+    if (tx->is_prepared())
+      tx->detach_prepared_tx();
     delete tx;
   }
   return HA_EXIT_SUCCESS;
@@ -5301,7 +5313,7 @@ static int rocksdb_init_func(void *const p) {
 #ifdef MARIAROCKS_NOT_YET
   rocksdb_hton->update_table_stats = rocksdb_update_table_stats;
 #endif // MARIAROCKS_NOT_YET
-  
+
   /*
   Not needed in MariaDB:
   rocksdb_hton->flush_logs = rocksdb_flush_wal;
diff --git a/storage/rocksdb/mysql-test/rocksdb/r/xa.result b/storage/rocksdb/mysql-test/rocksdb/r/xa.result
index 12ae2b474b6..8cb6f39bbac 100644
--- a/storage/rocksdb/mysql-test/rocksdb/r/xa.result
+++ b/storage/rocksdb/mysql-test/rocksdb/r/xa.result
@@ -1,6 +1,7 @@
-# 
-# MDEV-13155: XA recovery not supported for RocksDB (Just a testcase)
 #
+# MDEV-742 fixes
+#   MDEV-13155: XA recovery not supported for RocksDB
+# as well.
 call mtr.add_suppression("Found .* prepared XA transactions");
 connect  con1,localhost,root,,test;
 DROP TABLE IF EXISTS t1;
@@ -15,19 +16,55 @@ INSERT INTO t1 (a) VALUES (3);
 INSERT INTO t1 (a) VALUES (4);
 XA END 'xa2';
 XA PREPARE 'xa2';
+connect  con3,localhost,root,,test;
+XA START 'xa3';
+INSERT INTO t1 (a) VALUES (5);
+INSERT INTO t1 (a) VALUES (6);
+XA END 'xa3';
+XA PREPARE 'xa3';
+disconnect con3;
 connection default;
 SELECT * FROM t1;
 a
+Must be all three XA:s in
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	3	0	xa3
+1	3	0	xa1
+1	3	0	xa2
 # restart
 connect  con3,localhost,root,,test;
 XA RECOVER;
 formatID	gtrid_length	bqual_length	data
+1	3	0	xa3
 1	3	0	xa1
 1	3	0	xa2
 XA ROLLBACK 'xa1';
 XA COMMIT 'xa2';
+XA ROLLBACK 'xa3';
+SELECT a FROM t1;
+a
+3
+4
+connect  con4,localhost,root,,test;
+XA START 'xa4';
+INSERT INTO t1 (a) VALUES (7);
+INSERT INTO t1 (a) VALUES (8);
+XA END 'xa4';
+XA PREPARE 'xa4';
+connection default;
+# Now restart through graceful shutdown
+# restart
+connect  con5,localhost,root,,test;
+Must have 'xa4'
+XA RECOVER;
+formatID	gtrid_length	bqual_length	data
+1	3	0	xa4
+XA COMMIT 'xa4';
 SELECT a FROM t1;
 a
 3
 4
+7
+8
 DROP TABLE t1;
diff --git a/storage/rocksdb/mysql-test/rocksdb/t/xa.test b/storage/rocksdb/mysql-test/rocksdb/t/xa.test
index f8f381f0580..0c23e71df8c 100644
--- a/storage/rocksdb/mysql-test/rocksdb/t/xa.test
+++ b/storage/rocksdb/mysql-test/rocksdb/t/xa.test
@@ -1,6 +1,7 @@
---echo # 
---echo # MDEV-13155: XA recovery not supported for RocksDB (Just a testcase)
 --echo #
+--echo # MDEV-742 fixes
+--echo #   MDEV-13155: XA recovery not supported for RocksDB
+--echo # as well.
  
 call mtr.add_suppression("Found .* prepared XA transactions");
 
@@ -22,17 +23,51 @@ INSERT INTO t1 (a) VALUES (3);
 INSERT INTO t1 (a) VALUES (4);
 XA END 'xa2';
 XA PREPARE 'xa2';
- 
+
+--connect (con3,localhost,root,,test)
+XA START 'xa3';
+INSERT INTO t1 (a) VALUES (5);
+INSERT INTO t1 (a) VALUES (6);
+XA END 'xa3';
+XA PREPARE 'xa3';
+--disconnect con3
+
 --connection default
 SELECT * FROM t1;
 
+--echo Must be all three XA:s in
+XA RECOVER;
+
 --let $shutdown_timeout= 0
 --source include/restart_mysqld.inc
  
 --connect (con3,localhost,root,,test)
 --disable_abort_on_error
-XA RECOVER;
+XA RECOVER; # like above
 XA ROLLBACK 'xa1';
 XA COMMIT 'xa2';
+XA ROLLBACK 'xa3';
 SELECT a FROM t1;
+
+--connect (con4,localhost,root,,test)
+XA START 'xa4';
+INSERT INTO t1 (a) VALUES (7);
+INSERT INTO t1 (a) VALUES (8);
+XA END 'xa4';
+XA PREPARE 'xa4';
+
+--connection default
+--echo # Now restart through graceful shutdown
+--source include/restart_mysqld.inc
+
+
+--connect (con5,localhost,root,,test)
+--disable_abort_on_error
+
+--echo Must have 'xa4'
+XA RECOVER;
+XA COMMIT 'xa4';
+
+SELECT a FROM t1;
+
 DROP TABLE t1;
diff --git a/storage/rocksdb/mysql-test/rocksdb_rpl/r/rpl_xa.result b/storage/rocksdb/mysql-test/rocksdb_rpl/r/rpl_xa.result
new file mode 100644
index 00000000000..b4713c68390
--- /dev/null
+++ b/storage/rocksdb/mysql-test/rocksdb_rpl/r/rpl_xa.result
@@ -0,0 +1,50 @@
+include/master-slave.inc
+[connection master]
+connection master;
+create table t1 (a int, b int) engine=InnoDB;
+insert into t1 values(0, 0);
+xa start 't';
+insert into t1 values(1, 2);
+xa end 't';
+xa prepare 't';
+xa commit 't';
+connection slave;
+include/diff_tables.inc [master:t1, slave:t1]
+connection master;
+xa start 't';
+insert into t1 values(3, 4);
+xa end 't';
+xa prepare 't';
+xa rollback 't';
+connection slave;
+include/diff_tables.inc [master:t1, slave:t1]
+connection master;
+SET pseudo_slave_mode=1;
+create table t2 (a int) engine=InnoDB;
+xa start 't';
+insert into t1 values (5, 6);
+xa end 't';
+xa prepare 't';
+xa start 's';
+insert into t2 values (0);
+xa end 's';
+xa prepare 's';
+include/save_master_gtid.inc
+connection slave;
+include/sync_with_master_gtid.inc
+xa recover;
+formatID	gtrid_length	bqual_length	data
+1	1	0	t
+1	1	0	s
+connection master;
+xa commit 't';
+xa commit 's';
+SET pseudo_slave_mode=0;
+Warnings:
+Warning	1231	Slave applier execution mode not active, statement ineffective.
+connection slave;
+include/diff_tables.inc [master:t1, slave:t1]
+include/diff_tables.inc [master:t2, slave:t2]
+connection master;
+drop table t1, t2;
+include/rpl_end.inc
diff --git a/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_xa.inc b/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_xa.inc
new file mode 100644
index 00000000000..c1300c1e27a
--- /dev/null
+++ b/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_xa.inc
@@ -0,0 +1,70 @@
+#
+# This "body" file checks general properties of XA transaction replication
+# as of MDEV-7974.
+# Parameters:
+# --let rpl_xa_check= SELECT ...
+#
+connection master;
+create table t1 (a int, b int) engine=InnoDB;
+insert into t1 values(0, 0);
+xa start 't';
+insert into t1 values(1, 2);
+xa end 't';
+xa prepare 't';
+xa commit 't';
+
+sync_slave_with_master;
+let $diff_tables= master:t1, slave:t1;
+source include/diff_tables.inc;
+
+connection master;
+
+xa start 't';
+insert into t1 values(3, 4);
+xa end 't';
+xa prepare 't';
+xa rollback 't';
+
+sync_slave_with_master;
+let $diff_tables= master:t1, slave:t1;
+source include/diff_tables.inc;
+
+connection master;
+SET pseudo_slave_mode=1;
+create table t2 (a int) engine=InnoDB;
+xa start 't';
+insert into t1 values (5, 6);
+xa end 't';
+xa prepare 't';
+xa start 's';
+insert into t2 values (0);
+xa end 's';
+xa prepare 's';
+--source include/save_master_gtid.inc
+
+connection slave;
+source include/sync_with_master_gtid.inc;
+if ($rpl_xa_check)
+{
+  --eval $rpl_xa_check
+  if ($rpl_xa_verbose)
+  {
+    --eval SELECT $rpl_xa_check_lhs
+    --eval SELECT $rpl_xa_check_rhs
+  }
+}
+xa recover;
+
+connection master;
+xa commit 't';
+xa commit 's';
+SET pseudo_slave_mode=0;
+
+sync_slave_with_master;
+let $diff_tables= master:t1, slave:t1;
+source include/diff_tables.inc;
+let $diff_tables= master:t2, slave:t2;
+source include/diff_tables.inc;
+
+connection master;
+drop table t1, t2;
diff --git a/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_xa.test b/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_xa.test
new file mode 100644
index 00000000000..7d667aa96d2
--- /dev/null
+++ b/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_xa.test
@@ -0,0 +1,6 @@
+source include/have_rocksdb.inc;
+source include/master-slave.inc;
+source include/have_binlog_format_row.inc;
+
+source rpl_xa.inc;
+source include/rpl_end.inc;
diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/r/xa.result b/storage/tokudb/mysql-test/tokudb_mariadb/r/xa.result
index 4724a0af926..34233b6fd8d 100644
--- a/storage/tokudb/mysql-test/tokudb_mariadb/r/xa.result
+++ b/storage/tokudb/mysql-test/tokudb_mariadb/r/xa.result
@@ -65,4 +65,5 @@ a
 20
 disconnect con1;
 connection default;
+xa rollback 'testb',0x2030405060,11;
 drop table t1;
diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/t/xa.test b/storage/tokudb/mysql-test/tokudb_mariadb/t/xa.test
index dc5520a39b8..a6be07963f5 100644
--- a/storage/tokudb/mysql-test/tokudb_mariadb/t/xa.test
+++ b/storage/tokudb/mysql-test/tokudb_mariadb/t/xa.test
@@ -68,6 +68,9 @@ xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
 select * from t1;
 
 disconnect con1;
+xa recover;
+
 connection default;
+xa rollback 'testb',0x2030405060,11;
 drop table t1;