diff --git a/VERSION b/VERSION
index 508f021f35da6f695bf456dfd90903c54dbb3a5a..d05c93f6e73341e08de0c487831cc73be5b65d38 100644
--- a/VERSION
+++ b/VERSION
@@ -1,4 +1,4 @@
 MYSQL_VERSION_MAJOR=5
 MYSQL_VERSION_MINOR=5
-MYSQL_VERSION_PATCH=20
+MYSQL_VERSION_PATCH=21
 MYSQL_VERSION_EXTRA=
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 5ffde0cf1b02410024b26a5e0b60f5558809fa15..ccbd2fb4d22a2ec32475c28d41cd2815b3c77022 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -750,6 +750,31 @@ print_use_stmt(PRINT_EVENT_INFO* pinfo, const Query_log_event *ev)
 }
 
 
+/**
+   Print "SET skip_replication=..." statement when needed.
+
+   Not all servers support this (only MariaDB from some version on). So we
+   mark the SET to only execute from the version of MariaDB that supports it,
+   and also only output it if we actually see events with the flag set, to not
+   get spurious errors on MySQL@Oracle servers of higher version that do not
+   support the flag.
+
+   So we start out assuming @@skip_replication is 0, and only output a SET
+   statement when it changes.
+*/
+static void
+print_skip_replication_statement(PRINT_EVENT_INFO *pinfo, const Log_event *ev)
+{
+  int cur_val;
+
+  cur_val= (ev->flags & LOG_EVENT_SKIP_REPLICATION_F) != 0;
+  if (cur_val == pinfo->skip_replication)
+    return;                                     /* Not changed. */
+  fprintf(result_file, "/*!50521 SET skip_replication=%d*/%s\n",
+          cur_val, pinfo->delimiter);
+  pinfo->skip_replication= cur_val;
+}
+
 /**
   Prints the given event in base64 format.
 
@@ -893,7 +918,10 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
           goto end;
       }
       else
+      {
+        print_skip_replication_statement(print_event_info, ev);
         ev->print(result_file, print_event_info);
+      }
       break;
     }
 
@@ -923,7 +951,10 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
           goto end;
       }
       else
+      {
+        print_skip_replication_statement(print_event_info, ev);
         ce->print(result_file, print_event_info, TRUE);
+      }
 
       // If this binlog is not 3.23 ; why this test??
       if (glob_description_event->binlog_version >= 3)
@@ -1027,6 +1058,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
         if (fname)
         {
           convert_path_to_forward_slashes(fname);
+          print_skip_replication_statement(print_event_info, ev);
           exlq->print(result_file, print_event_info, fname);
         }
         else
@@ -1156,6 +1188,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
       /* FALL THROUGH */
     }
     default:
+      print_skip_replication_statement(print_event_info, ev);
       ev->print(result_file, print_event_info);
     }
   }
diff --git a/mysql-test/r/mysqld--help-win.result.THIS b/mysql-test/r/mysqld--help-win.result.THIS
index 05cbcda7129e8486a25c9ed8e570980fcb9da4bf..1edd8b36430f79be8b483d2a3076a93d61e05e06 100644
--- a/mysql-test/r/mysqld--help-win.result.THIS
+++ b/mysql-test/r/mysqld--help-win.result.THIS
@@ -620,6 +620,14 @@ The following options may be given as the first argument:
  directive multiple times, once for each table. This will
  work for cross-database updates, in contrast to
  replicate-do-db.
+ --replicate-events-marked-for-skip=name 
+ Whether the slave should replicate events that were
+ created with @@skip_replication=1 on the master. Default
+ REPLICATE (no events are skipped). Other values are
+ FILTER_ON_SLAVE (events will be sent by the master but
+ ignored by the slave) and FILTER_ON_MASTER (events marked
+ with @@skip_replication=1 will be filtered on the master
+ and never be sent to the slave).
  --replicate-ignore-db=name 
  Tells the slave thread to not replicate to the specified
  database. To specify more than one database to ignore,
@@ -1029,6 +1037,7 @@ relay-log-purge TRUE
 relay-log-recovery FALSE
 relay-log-space-limit 0
 replicate-annotate-row-events FALSE
+replicate-events-marked-for-skip replicate
 replicate-same-server-id FALSE
 report-host (No default value)
 report-password (No default value)
diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result
index 94d7465d39bfb8b42b95d243638cefc68cf60df4..b3240d7c4f19ceae90727afcf0384f1b65daba47 100644
--- a/mysql-test/r/mysqld--help.result
+++ b/mysql-test/r/mysqld--help.result
@@ -620,6 +620,14 @@ The following options may be given as the first argument:
  directive multiple times, once for each table. This will
  work for cross-database updates, in contrast to
  replicate-do-db.
+ --replicate-events-marked-for-skip=name 
+ Whether the slave should replicate events that were
+ created with @@skip_replication=1 on the master. Default
+ REPLICATE (no events are skipped). Other values are
+ FILTER_ON_SLAVE (events will be sent by the master but
+ ignored by the slave) and FILTER_ON_MASTER (events marked
+ with @@skip_replication=1 will be filtered on the master
+ and never be sent to the slave).
  --replicate-ignore-db=name 
  Tells the slave thread to not replicate to the specified
  database. To specify more than one database to ignore,
@@ -1021,6 +1029,7 @@ relay-log-purge TRUE
 relay-log-recovery FALSE
 relay-log-space-limit 0
 replicate-annotate-row-events FALSE
+replicate-events-marked-for-skip replicate
 replicate-same-server-id FALSE
 report-host (No default value)
 report-password (No default value)
diff --git a/mysql-test/suite/rpl/r/rpl_skip_replication.result b/mysql-test/suite/rpl/r/rpl_skip_replication.result
new file mode 100644
index 0000000000000000000000000000000000000000..c19f9009021b4f27a5630ec13fe321ad075b51b9
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_skip_replication.result
@@ -0,0 +1,252 @@
+include/master-slave.inc
+[connection master]
+CREATE USER 'nonsuperuser'@'127.0.0.1';
+GRANT ALTER,CREATE,DELETE,DROP,EVENT,INSERT,PROCESS,REPLICATION SLAVE,
+SELECT,UPDATE ON *.* TO 'nonsuperuser'@'127.0.0.1';
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+DROP USER'nonsuperuser'@'127.0.0.1';
+SELECT @@global.replicate_events_marked_for_skip;
+@@global.replicate_events_marked_for_skip
+replicate
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE;
+ERROR HY000: This operation cannot be performed with a running slave; run STOP SLAVE first
+SELECT @@global.replicate_events_marked_for_skip;
+@@global.replicate_events_marked_for_skip
+replicate
+STOP SLAVE;
+SET SESSION replicate_events_marked_for_skip=FILTER_ON_MASTER;
+ERROR HY000: Variable 'replicate_events_marked_for_skip' is a GLOBAL variable and should be set with SET GLOBAL
+SELECT @@global.replicate_events_marked_for_skip;
+@@global.replicate_events_marked_for_skip
+replicate
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER;
+SELECT @@global.replicate_events_marked_for_skip;
+@@global.replicate_events_marked_for_skip
+filter_on_master
+START SLAVE;
+SELECT @@skip_replication;
+@@skip_replication
+0
+SET GLOBAL skip_replication=1;
+ERROR HY000: Variable 'skip_replication' is a SESSION variable and can't be used with SET GLOBAL
+SELECT @@skip_replication;
+@@skip_replication
+0
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=innodb;
+INSERT INTO t1(a) VALUES (1);
+INSERT INTO t2(a) VALUES (1);
+SET skip_replication=1;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
+INSERT INTO t1(a) VALUES (2);
+INSERT INTO t2(a) VALUES (2);
+FLUSH NO_WRITE_TO_BINLOG LOGS;
+SHOW TABLES;
+Tables_in_test
+t1
+t2
+SELECT * FROM t1;
+a	b
+1	NULL
+SELECT * FROM t2;
+a	b
+1	NULL
+DROP TABLE t3;
+FLUSH NO_WRITE_TO_BINLOG LOGS;
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE;
+START SLAVE;
+SET skip_replication=1;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
+INSERT INTO t1(a) VALUES (3);
+INSERT INTO t2(a) VALUES (3);
+FLUSH NO_WRITE_TO_BINLOG LOGS;
+SHOW TABLES;
+Tables_in_test
+t1
+t2
+SELECT * FROM t1;
+a	b
+1	NULL
+SELECT * FROM t2;
+a	b
+1	NULL
+DROP TABLE t3;
+FLUSH NO_WRITE_TO_BINLOG LOGS;
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=REPLICATE;
+START SLAVE;
+SET skip_replication=1;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
+INSERT INTO t3(a) VALUES(2);
+SELECT * FROM t3;
+a	b
+2	NULL
+DROP TABLE t3;
+TRUNCATE t1;
+RESET MASTER;
+SET skip_replication=0;
+INSERT INTO t1 VALUES (1,0);
+SET skip_replication=1;
+INSERT INTO t1 VALUES (2,0);
+SET skip_replication=0;
+INSERT INTO t1 VALUES (3,0);
+SELECT * FROM t1 ORDER by a;
+a	b
+1	0
+2	0
+3	0
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER;
+TRUNCATE t1;
+SELECT * FROM t1 ORDER by a;
+a	b
+1	0
+2	0
+3	0
+START SLAVE;
+SELECT * FROM t1 ORDER by a;
+a	b
+1	0
+3	0
+TRUNCATE t1;
+STOP SLAVE;
+SET GLOBAL sql_slave_skip_counter=6;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE;
+START SLAVE;
+SET @old_binlog_format= @@binlog_format;
+SET binlog_format= statement;
+SET skip_replication=0;
+INSERT INTO t1 VALUES (1,5);
+SET skip_replication=1;
+INSERT INTO t1 VALUES (2,5);
+SET skip_replication=0;
+INSERT INTO t1 VALUES (3,5);
+INSERT INTO t1 VALUES (4,5);
+SET binlog_format= @old_binlog_format;
+SELECT * FROM t1;
+a	b
+4	5
+include/stop_slave.inc
+SET @old_slave_binlog_format= @@global.binlog_format;
+SET GLOBAL binlog_format= row;
+include/start_slave.inc
+TRUNCATE t1;
+SET @old_binlog_format= @@binlog_format;
+SET binlog_format= row;
+BINLOG 'wlZOTw8BAAAA8QAAAPUAAAAAAAQANS41LjIxLU1hcmlhREItZGVidWctbG9nAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA2QAEGggAAAAICAgCAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAA371saA==';
+BINLOG 'wlZOTxMBAAAAKgAAAGMBAAAAgCkAAAAAAAEABHRlc3QAAnQxAAIDAwAC
+wlZOTxcBAAAAJgAAAIkBAAAAgCkAAAAAAAEAAv/8AQAAAAgAAAA=';
+BINLOG 'wlZOTxMBAAAAKgAAADwCAAAAACkAAAAAAAEABHRlc3QAAnQxAAIDAwAC
+wlZOTxcBAAAAJgAAAGICAAAAACkAAAAAAAEAAv/8AgAAAAgAAAA=';
+SET binlog_format= @old_binlog_format;
+SELECT * FROM t1 ORDER BY a;
+a	b
+1	8
+2	8
+SELECT * FROM t1 ORDER by a;
+a	b
+2	8
+include/stop_slave.inc
+SET GLOBAL binlog_format= @old_slave_binlog_format;
+include/start_slave.inc
+SET skip_replication=0;
+BEGIN;
+SET skip_replication=0;
+ERROR HY000: Cannot modify @@session.skip_replication inside a transaction
+SET skip_replication=1;
+ERROR HY000: Cannot modify @@session.skip_replication inside a transaction
+ROLLBACK;
+SET skip_replication=1;
+BEGIN;
+SET skip_replication=0;
+ERROR HY000: Cannot modify @@session.skip_replication inside a transaction
+SET skip_replication=1;
+ERROR HY000: Cannot modify @@session.skip_replication inside a transaction
+COMMIT;
+SET autocommit=0;
+INSERT INTO t2(a) VALUES(100);
+SET skip_replication=1;
+ERROR HY000: Cannot modify @@session.skip_replication inside a transaction
+ROLLBACK;
+SET autocommit=1;
+SET skip_replication=1;
+CREATE FUNCTION foo (x INT) RETURNS INT BEGIN SET SESSION skip_replication=x; RETURN x; END|
+CREATE PROCEDURE bar(x INT) BEGIN SET SESSION skip_replication=x; END|
+CREATE FUNCTION baz (x INT) RETURNS INT BEGIN CALL bar(x); RETURN x; END|
+SELECT foo(0);
+ERROR HY000: Cannot modify @@session.skip_replication inside a stored function or trigger
+SELECT baz(0);
+ERROR HY000: Cannot modify @@session.skip_replication inside a stored function or trigger
+SET @a= foo(1);
+ERROR HY000: Cannot modify @@session.skip_replication inside a stored function or trigger
+SET @a= baz(1);
+ERROR HY000: Cannot modify @@session.skip_replication inside a stored function or trigger
+UPDATE t2 SET b=foo(0);
+ERROR HY000: Cannot modify @@session.skip_replication inside a stored function or trigger
+UPDATE t2 SET b=baz(0);
+ERROR HY000: Cannot modify @@session.skip_replication inside a stored function or trigger
+INSERT INTO t1 VALUES (101, foo(1));
+ERROR HY000: Cannot modify @@session.skip_replication inside a stored function or trigger
+INSERT INTO t1 VALUES (101, baz(0));
+ERROR HY000: Cannot modify @@session.skip_replication inside a stored function or trigger
+SELECT @@skip_replication;
+@@skip_replication
+1
+CALL bar(0);
+SELECT @@skip_replication;
+@@skip_replication
+0
+CALL bar(1);
+SELECT @@skip_replication;
+@@skip_replication
+1
+DROP FUNCTION foo;
+DROP PROCEDURE bar;
+DROP FUNCTION baz;
+SET skip_replication= 0;
+TRUNCATE t1;
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER;
+START SLAVE IO_THREAD;
+SET skip_replication= 1;
+INSERT INTO t1(a) VALUES (1);
+SET skip_replication= 0;
+INSERT INTO t1(a) VALUES (2);
+include/save_master_pos.inc
+include/sync_io_with_master.inc
+STOP SLAVE IO_THREAD;
+SET GLOBAL replicate_events_marked_for_skip=REPLICATE;
+START SLAVE;
+SELECT * FROM t1;
+a	b
+2	NULL
+SET skip_replication= 0;
+TRUNCATE t1;
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE;
+START SLAVE IO_THREAD;
+SET skip_replication= 1;
+INSERT INTO t1(a) VALUES (1);
+SET skip_replication= 0;
+INSERT INTO t1(a) VALUES (2);
+include/save_master_pos.inc
+include/sync_io_with_master.inc
+STOP SLAVE IO_THREAD;
+SET GLOBAL replicate_events_marked_for_skip=REPLICATE;
+START SLAVE;
+SELECT * FROM t1 ORDER BY a;
+a	b
+1	NULL
+2	NULL
+SET skip_replication=0;
+DROP TABLE t1,t2;
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=REPLICATE;
+START SLAVE;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_skip_replication.test b/mysql-test/suite/rpl/t/rpl_skip_replication.test
new file mode 100644
index 0000000000000000000000000000000000000000..f815554d4afc4de0cb2abeab98769f93ae40f3ce
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_skip_replication.test
@@ -0,0 +1,377 @@
+--source include/master-slave.inc
+--source include/have_innodb.inc
+
+connection slave;
+# Test that SUPER is required to change @@replicate_events_marked_for_skip.
+CREATE USER 'nonsuperuser'@'127.0.0.1';
+GRANT ALTER,CREATE,DELETE,DROP,EVENT,INSERT,PROCESS,REPLICATION SLAVE,
+      SELECT,UPDATE ON *.* TO 'nonsuperuser'@'127.0.0.1';
+connect(nonpriv, 127.0.0.1, nonsuperuser,, test, $SLAVE_MYPORT,);
+connection nonpriv;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER;
+disconnect nonpriv;
+connection slave;
+DROP USER'nonsuperuser'@'127.0.0.1';
+
+SELECT @@global.replicate_events_marked_for_skip;
+--error ER_SLAVE_MUST_STOP
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE;
+SELECT @@global.replicate_events_marked_for_skip;
+STOP SLAVE;
+--error ER_GLOBAL_VARIABLE
+SET SESSION replicate_events_marked_for_skip=FILTER_ON_MASTER;
+SELECT @@global.replicate_events_marked_for_skip;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER;
+SELECT @@global.replicate_events_marked_for_skip;
+START SLAVE;
+
+connection master;
+SELECT @@skip_replication;
+--error ER_LOCAL_VARIABLE
+SET GLOBAL skip_replication=1;
+SELECT @@skip_replication;
+
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=innodb;
+INSERT INTO t1(a) VALUES (1);
+INSERT INTO t2(a) VALUES (1);
+
+
+# Test that master-side filtering works.
+SET skip_replication=1;
+
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
+INSERT INTO t1(a) VALUES (2);
+INSERT INTO t2(a) VALUES (2);
+
+# Inject a rotate event in the binlog stream sent to slave (otherwise we will
+# fail sync_slave_with_master as the last event on the master is not present
+# on the slave).
+FLUSH NO_WRITE_TO_BINLOG LOGS;
+
+sync_slave_with_master;
+connection slave;
+SHOW TABLES;
+SELECT * FROM t1;
+SELECT * FROM t2;
+
+connection master;
+DROP TABLE t3;
+
+FLUSH NO_WRITE_TO_BINLOG LOGS;
+sync_slave_with_master;
+
+
+# Test that slave-side filtering works.
+connection slave;
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE;
+START SLAVE;
+
+connection master;
+SET skip_replication=1;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
+INSERT INTO t1(a) VALUES (3);
+INSERT INTO t2(a) VALUES (3);
+
+# Inject a rotate event in the binlog stream sent to slave (otherwise we will
+# fail sync_slave_with_master as the last event on the master is not present
+# on the slave).
+FLUSH NO_WRITE_TO_BINLOG LOGS;
+
+sync_slave_with_master;
+connection slave;
+SHOW TABLES;
+SELECT * FROM t1;
+SELECT * FROM t2;
+
+connection master;
+DROP TABLE t3;
+
+FLUSH NO_WRITE_TO_BINLOG LOGS;
+sync_slave_with_master;
+connection slave;
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=REPLICATE;
+START SLAVE;
+
+
+# Test that events with @@skip_replication=1 are not filtered when filtering is
+# not set on slave.
+connection master;
+SET skip_replication=1;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=myisam;
+INSERT INTO t3(a) VALUES(2);
+sync_slave_with_master;
+connection slave;
+SELECT * FROM t3;
+connection master;
+DROP TABLE t3;
+
+#
+# Test that the slave will preserve the @@skip_replication flag in its
+# own binlog.
+#
+
+TRUNCATE t1;
+sync_slave_with_master;
+connection slave;
+RESET MASTER;
+
+connection master;
+SET skip_replication=0;
+INSERT INTO t1 VALUES (1,0);
+SET skip_replication=1;
+INSERT INTO t1 VALUES (2,0);
+SET skip_replication=0;
+INSERT INTO t1 VALUES (3,0);
+
+sync_slave_with_master;
+connection slave;
+# Since slave has @@replicate_events_marked_for_skip=REPLICATE, it should have
+# applied all events.
+SELECT * FROM t1 ORDER by a;
+
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER;
+let $SLAVE_DATADIR= `select @@datadir`;
+
+connection master;
+TRUNCATE t1;
+
+# Now apply the slave binlog to the master, to check that both the slave
+# and mysqlbinlog will preserve the @@skip_replication flag.
+--exec $MYSQL_BINLOG $SLAVE_DATADIR/slave-bin.000001 > $MYSQLTEST_VARDIR/tmp/rpl_skip_replication.binlog
+--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/rpl_skip_replication.binlog
+
+# The master should have all three events.
+SELECT * FROM t1 ORDER by a;
+
+# The slave should be missing event 2, which is marked with the
+# @@skip_replication flag.
+
+connection slave;
+START SLAVE;
+
+connection master;
+sync_slave_with_master;
+
+connection slave;
+SELECT * FROM t1 ORDER by a;
+
+#
+# Test that @@sql_slave_skip_counter does not count skipped @@skip_replication
+# events.
+#
+
+connection master;
+TRUNCATE t1;
+
+sync_slave_with_master;
+connection slave;
+STOP SLAVE;
+# We will skip two INSERTs (in addition to any skipped due to
+# @@skip_replication). Since from 5.5 every statement is wrapped in
+# BEGIN ... END, we need to skip 6 events for this.
+SET GLOBAL sql_slave_skip_counter=6;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE;
+START SLAVE;
+
+connection master;
+# Need to fix @@binlog_format to get consistent event count.
+SET @old_binlog_format= @@binlog_format;
+SET binlog_format= statement;
+SET skip_replication=0;
+INSERT INTO t1 VALUES (1,5);
+SET skip_replication=1;
+INSERT INTO t1 VALUES (2,5);
+SET skip_replication=0;
+INSERT INTO t1 VALUES (3,5);
+INSERT INTO t1 VALUES (4,5);
+SET binlog_format= @old_binlog_format;
+
+sync_slave_with_master;
+connection slave;
+
+# The slave should have skipped the first three inserts (number 1 and 3 due
+# to @@sql_slave_skip_counter=2, number 2 due to
+# @@replicate_events_marked_for_skip=FILTER_ON_SLAVE). So only number 4
+# should be left.
+SELECT * FROM t1;
+
+
+#
+# Check that BINLOG statement preserves the @@skip_replication flag.
+#
+connection slave;
+# Need row @@binlog_format for BINLOG statements containing row events.
+--source include/stop_slave.inc
+SET @old_slave_binlog_format= @@global.binlog_format;
+SET GLOBAL binlog_format= row;
+--source include/start_slave.inc
+
+connection master;
+TRUNCATE t1;
+
+SET @old_binlog_format= @@binlog_format;
+SET binlog_format= row;
+# Format description log event.
+BINLOG 'wlZOTw8BAAAA8QAAAPUAAAAAAAQANS41LjIxLU1hcmlhREItZGVidWctbG9nAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAA2QAEGggAAAAICAgCAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAA371saA==';
+# INSERT INTO t1 VALUES (1,8)  # with @@skip_replication=1
+BINLOG 'wlZOTxMBAAAAKgAAAGMBAAAAgCkAAAAAAAEABHRlc3QAAnQxAAIDAwAC
+wlZOTxcBAAAAJgAAAIkBAAAAgCkAAAAAAAEAAv/8AQAAAAgAAAA=';
+# INSERT INTO t1 VALUES (2,8)  # with @@skip_replication=0
+BINLOG 'wlZOTxMBAAAAKgAAADwCAAAAACkAAAAAAAEABHRlc3QAAnQxAAIDAwAC
+wlZOTxcBAAAAJgAAAGICAAAAACkAAAAAAAEAAv/8AgAAAAgAAAA=';
+SET binlog_format= @old_binlog_format;
+
+SELECT * FROM t1 ORDER BY a;
+sync_slave_with_master;
+connection slave;
+# Slave should have only the second insert, the first should be ignored due to
+# the @@skip_replication flag.
+SELECT * FROM t1 ORDER by a;
+
+--source include/stop_slave.inc
+SET GLOBAL binlog_format= @old_slave_binlog_format;
+--source include/start_slave.inc
+
+
+# Test that it is not possible to change @@skip_replication inside a
+# transaction or statement, thereby replicating only parts of statements
+# or transactions.
+connection master;
+SET skip_replication=0;
+
+BEGIN;
+--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION
+SET skip_replication=0;
+--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION
+SET skip_replication=1;
+ROLLBACK;
+SET skip_replication=1;
+BEGIN;
+--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION
+SET skip_replication=0;
+--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION
+SET skip_replication=1;
+COMMIT;
+SET autocommit=0;
+INSERT INTO t2(a) VALUES(100);
+--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION
+SET skip_replication=1;
+ROLLBACK;
+SET autocommit=1;
+
+SET skip_replication=1;
+--delimiter |
+CREATE FUNCTION foo (x INT) RETURNS INT BEGIN SET SESSION skip_replication=x; RETURN x; END|
+CREATE PROCEDURE bar(x INT) BEGIN SET SESSION skip_replication=x; END|
+CREATE FUNCTION baz (x INT) RETURNS INT BEGIN CALL bar(x); RETURN x; END|
+--delimiter ;
+--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION
+SELECT foo(0);
+--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION
+SELECT baz(0);
+--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION
+SET @a= foo(1);
+--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION
+SET @a= baz(1);
+--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION
+UPDATE t2 SET b=foo(0);
+--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION
+UPDATE t2 SET b=baz(0);
+--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION
+INSERT INTO t1 VALUES (101, foo(1));
+--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION
+INSERT INTO t1 VALUES (101, baz(0));
+SELECT @@skip_replication;
+CALL bar(0);
+SELECT @@skip_replication;
+CALL bar(1);
+SELECT @@skip_replication;
+DROP FUNCTION foo;
+DROP PROCEDURE bar;
+DROP FUNCTION baz;
+
+
+# Test that master-side filtering happens on the master side, and that
+# slave-side filtering happens on the slave.
+
+# First test that events do not reach the slave when master-side filtering
+# is configured. Do this by replicating first with only the IO thread running
+# and master-side filtering; then change to no filtering and start the SQL
+# thread. This should still skip the events, as master-side filtering
+# means the events never reached the slave.
+connection master;
+SET skip_replication= 0;
+TRUNCATE t1;
+sync_slave_with_master;
+connection slave;
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_MASTER;
+START SLAVE IO_THREAD;
+connection master;
+SET skip_replication= 1;
+INSERT INTO t1(a) VALUES (1);
+SET skip_replication= 0;
+INSERT INTO t1(a) VALUES (2);
+--source include/save_master_pos.inc
+connection slave;
+--source include/sync_io_with_master.inc
+STOP SLAVE IO_THREAD;
+SET GLOBAL replicate_events_marked_for_skip=REPLICATE;
+START SLAVE;
+connection master;
+sync_slave_with_master;
+connection slave;
+# Now only the second insert of (2) should be visible, as the first was
+# filtered on the master, so even though the SQL thread ran without skipping
+# events, it will never see the event in the first place.
+SELECT * FROM t1;
+
+# Now tests that when slave-side filtering is configured, events _do_ reach
+# the slave.
+connection master;
+SET skip_replication= 0;
+TRUNCATE t1;
+sync_slave_with_master;
+connection slave;
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=FILTER_ON_SLAVE;
+START SLAVE IO_THREAD;
+connection master;
+SET skip_replication= 1;
+INSERT INTO t1(a) VALUES (1);
+SET skip_replication= 0;
+INSERT INTO t1(a) VALUES (2);
+--source include/save_master_pos.inc
+connection slave;
+--source include/sync_io_with_master.inc
+STOP SLAVE IO_THREAD;
+SET GLOBAL replicate_events_marked_for_skip=REPLICATE;
+START SLAVE;
+connection master;
+sync_slave_with_master;
+connection slave;
+# Now both inserts should be visible. Since filtering was configured to be
+# slave-side, the event is in the relay log, and when the SQL thread ran we
+# had disabled filtering again.
+SELECT * FROM t1 ORDER BY a;
+
+
+# Clean up.
+connection master;
+SET skip_replication=0;
+DROP TABLE t1,t2;
+connection slave;
+STOP SLAVE;
+SET GLOBAL replicate_events_marked_for_skip=REPLICATE;
+START SLAVE;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/sys_vars/r/replicate_events_marked_for_skip_basic.result b/mysql-test/suite/sys_vars/r/replicate_events_marked_for_skip_basic.result
new file mode 100644
index 0000000000000000000000000000000000000000..8bc7c845e0b6c9bd25b52b4ceac8716d0340fb83
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/replicate_events_marked_for_skip_basic.result
@@ -0,0 +1,35 @@
+#
+# Basic testing of replicate_events_marked_for_skip.
+#
+SET @save_replicate_events_marked_for_skip = @@GLOBAL.replicate_events_marked_for_skip;
+SELECT @save_replicate_events_marked_for_skip;
+@save_replicate_events_marked_for_skip
+replicate
+# Scope.
+SET @@SESSION.replicate_events_marked_for_skip = "";
+ERROR HY000: Variable 'replicate_events_marked_for_skip' is a GLOBAL variable and should be set with SET GLOBAL
+SELECT @@SESSION.replicate_events_marked_for_skip;
+ERROR HY000: Variable 'replicate_events_marked_for_skip' is a GLOBAL variable
+# Argument syntax.
+SET @@GLOBAL.replicate_events_marked_for_skip=filter_on_master;
+SELECT @@GLOBAL.replicate_events_marked_for_skip;
+@@GLOBAL.replicate_events_marked_for_skip
+filter_on_master
+SET @@GLOBAL.replicate_events_marked_for_skip=filter_on_slave;
+SELECT @@GLOBAL.replicate_events_marked_for_skip;
+@@GLOBAL.replicate_events_marked_for_skip
+filter_on_slave
+SET @@GLOBAL.replicate_events_marked_for_skip=replicate;
+SELECT @@GLOBAL.replicate_events_marked_for_skip;
+@@GLOBAL.replicate_events_marked_for_skip
+replicate
+SET @@GLOBAL.replicate_events_marked_for_skip=filter;
+ERROR 42000: Variable 'replicate_events_marked_for_skip' can't be set to the value of 'filter'
+SELECT @@GLOBAL.replicate_events_marked_for_skip;
+@@GLOBAL.replicate_events_marked_for_skip
+replicate
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_events_marked_for_skip';
+VARIABLE_NAME	VARIABLE_VALUE
+REPLICATE_EVENTS_MARKED_FOR_SKIP	replicate
+# Cleanup.
+SET @@GLOBAL.replicate_events_marked_for_skip = @save_replicate_events_marked_for_skip;
diff --git a/mysql-test/suite/sys_vars/r/skip_replication_basic.result b/mysql-test/suite/sys_vars/r/skip_replication_basic.result
new file mode 100644
index 0000000000000000000000000000000000000000..bb04df169a14824716c4ad6ec6b399f751daf1eb
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/skip_replication_basic.result
@@ -0,0 +1,34 @@
+select @@global.skip_replication;
+ERROR HY000: Variable 'skip_replication' is a SESSION variable
+select @@session.skip_replication between 1 and 10000;
+@@session.skip_replication between 1 and 10000
+0
+should be empty
+show global variables like 'skip_replication';
+Variable_name	Value
+show session variables like 'skip_replication';
+Variable_name	Value
+skip_replication	OFF
+should be empty
+select * from information_schema.global_variables where variable_name='skip_replication';
+VARIABLE_NAME	VARIABLE_VALUE
+select @@session.skip_replication = variable_value from information_schema.session_variables where variable_name='skip_replication';
+@@session.skip_replication = variable_value
+1
+Warnings:
+Warning	1292	Truncated incorrect DOUBLE value: 'OFF'
+set session skip_replication=0;
+select @@session.skip_replication;
+@@session.skip_replication
+0
+set session skip_replication=1;
+select @@session.skip_replication;
+@@session.skip_replication
+1
+select * from information_schema.global_variables where variable_name='skip_replication';
+VARIABLE_NAME	VARIABLE_VALUE
+select variable_value from information_schema.session_variables where variable_name='skip_replication';
+variable_value
+ON
+set global skip_replication=1;
+ERROR HY000: Variable 'skip_replication' is a SESSION variable and can't be used with SET GLOBAL
diff --git a/mysql-test/suite/sys_vars/t/replicate_events_marked_for_skip_basic.test b/mysql-test/suite/sys_vars/t/replicate_events_marked_for_skip_basic.test
new file mode 100644
index 0000000000000000000000000000000000000000..ecbbb821299178cb10697a50357c2413cf214306
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/replicate_events_marked_for_skip_basic.test
@@ -0,0 +1,31 @@
+source include/not_embedded.inc;
+
+--echo #
+--echo # Basic testing of replicate_events_marked_for_skip.
+--echo #
+
+SET @save_replicate_events_marked_for_skip = @@GLOBAL.replicate_events_marked_for_skip;
+SELECT @save_replicate_events_marked_for_skip;
+
+--echo # Scope.
+
+--error ER_GLOBAL_VARIABLE
+SET @@SESSION.replicate_events_marked_for_skip = "";
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@SESSION.replicate_events_marked_for_skip;
+
+--echo # Argument syntax.
+
+SET @@GLOBAL.replicate_events_marked_for_skip=filter_on_master;
+SELECT @@GLOBAL.replicate_events_marked_for_skip;
+SET @@GLOBAL.replicate_events_marked_for_skip=filter_on_slave;
+SELECT @@GLOBAL.replicate_events_marked_for_skip;
+SET @@GLOBAL.replicate_events_marked_for_skip=replicate;
+SELECT @@GLOBAL.replicate_events_marked_for_skip;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@GLOBAL.replicate_events_marked_for_skip=filter;
+SELECT @@GLOBAL.replicate_events_marked_for_skip;
+SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='replicate_events_marked_for_skip';
+
+--echo # Cleanup.
+SET @@GLOBAL.replicate_events_marked_for_skip = @save_replicate_events_marked_for_skip;
diff --git a/mysql-test/suite/sys_vars/t/skip_replication_basic.test b/mysql-test/suite/sys_vars/t/skip_replication_basic.test
new file mode 100644
index 0000000000000000000000000000000000000000..da1b6c5f2e17c42f20934819e0ca527c4de41f97
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/skip_replication_basic.test
@@ -0,0 +1,30 @@
+# exists as a session only
+ 
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+select @@global.skip_replication;
+
+# Check the variable has a valid numeric value (assumed to be less then 10000)
+select @@session.skip_replication between 1 and 10000;
+
+--echo should be empty
+show global variables like 'skip_replication';
+show session variables like 'skip_replication';
+
+# Global I_S variable is empty
+--echo should be empty
+select * from information_schema.global_variables where variable_name='skip_replication';
+
+# Check that I_S value is same as variable
+select @@session.skip_replication = variable_value from information_schema.session_variables where variable_name='skip_replication';
+
+#
+# show that it's writable
+#
+set session skip_replication=0;
+select @@session.skip_replication;
+set session skip_replication=1;
+select @@session.skip_replication;
+select * from information_schema.global_variables where variable_name='skip_replication';
+select variable_value from information_schema.session_variables where variable_name='skip_replication';
+--error ER_LOCAL_VARIABLE
+set global skip_replication=1;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index bd5f6306c470adc970152756805f31f2cfa338a7..cec0785a08865a34e69ffb4fbbf5f24b7a12d784 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -729,7 +729,7 @@ const char* Log_event::get_type_str()
 
 #ifndef MYSQL_CLIENT
 Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
-  :log_pos(0), temp_buf(0), exec_time(0), flags(flags_arg),
+  :log_pos(0), temp_buf(0), exec_time(0),
    crc(0), thd(thd_arg),
    checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF)
 {
@@ -741,6 +741,9 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
     cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
   else
     cache_type= Log_event::EVENT_STMT_CACHE;
+  flags= flags_arg |
+    (thd->variables.option_bits & OPTION_SKIP_REPLICATION ?
+     LOG_EVENT_SKIP_REPLICATION_F : 0);
 }
 
 /**
@@ -891,7 +894,9 @@ Log_event::do_shall_skip(Relay_log_info *rli)
                       rli->replicate_same_server_id,
                       rli->slave_skip_counter));
   if ((server_id == ::server_id && !rli->replicate_same_server_id) ||
-      (rli->slave_skip_counter == 1 && rli->is_in_group()))
+      (rli->slave_skip_counter == 1 && rli->is_in_group()) ||
+      (flags & LOG_EVENT_SKIP_REPLICATION_F &&
+       opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE))
     return EVENT_SKIP_IGNORE;
   if (rli->slave_skip_counter > 0)
     return EVENT_SKIP_COUNT;
@@ -3901,6 +3906,14 @@ Query_log_event::do_shall_skip(Relay_log_info *rli)
   DBUG_PRINT("debug", ("query: %s; q_len: %d", query, q_len));
   DBUG_ASSERT(query && q_len > 0);
 
+  /*
+    An event skipped due to @@skip_replication must not be counted towards the
+    number of events to be skipped due to @@sql_slave_skip_counter.
+  */
+  if (flags & LOG_EVENT_SKIP_REPLICATION_F &&
+      opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE)
+    DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+
   if (rli->slave_skip_counter > 0)
   {
     if (strcmp("BEGIN", query) == 0)
@@ -10806,7 +10819,7 @@ st_print_event_info::st_print_event_info()
    auto_increment_increment(0),auto_increment_offset(0), charset_inited(0),
    lc_time_names_number(~0),
    charset_database_number(ILLEGAL_CHARSET_INFO_NUMBER),
-   thread_id(0), thread_id_printed(false),
+   thread_id(0), thread_id_printed(false), skip_replication(0),
    base64_output_mode(BASE64_OUTPUT_UNSPEC), printed_fd_event(FALSE)
 {
   /*
diff --git a/sql/log_event.h b/sql/log_event.h
index 2f8854dd48883aa107e3a28291be031ab9e4d208..22e28c7ae13bac87bb807b62aa5531a464671f58 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -504,6 +504,19 @@ struct sql_ex_info
 */
 #define LOG_EVENT_RELAY_LOG_F 0x40
 
+/**
+   @def LOG_EVENT_SKIP_REPLICATION_F
+
+   Flag set by application creating the event (with @@skip_replication); the
+   slave will skip replication of such events if
+   --replicate-events-marked-for-skip is not set to REPLICATE.
+
+   This is a MariaDB flag; we allocate it from the end of the available
+   values to reduce risk of conflict with new MySQL flags.
+*/
+#define LOG_EVENT_SKIP_REPLICATION_F 0x8000
+
+
 /**
   @def OPTIONS_WRITTEN_TO_BIN_LOG
 
@@ -701,6 +714,11 @@ typedef struct st_print_event_info
   uint charset_database_number;
   uint thread_id;
   bool thread_id_printed;
+  /*
+    Track when @@skip_replication changes so we need to output a SET
+    statement for it.
+  */
+  int skip_replication;
 
   st_print_event_info();
 
@@ -993,8 +1011,8 @@ public:
 
   /**
     Some 16 flags. See the definitions above for LOG_EVENT_TIME_F,
-    LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, and
-    LOG_EVENT_SUPPRESS_USE_F for notes.
+    LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F,
+    LOG_EVENT_SUPPRESS_USE_F, and LOG_EVENT_SKIP_REPLICATION_F for notes.
   */
   uint16 flags;
 
@@ -4143,6 +4161,8 @@ public:
     m_message.str= NULL;                    /* Just as a precaution */
     m_message.length= 0;
     set_direct_logging();
+    /* Replicate the incident irregardless of @@skip_replication. */
+    flags&= ~LOG_EVENT_SKIP_REPLICATION_F;
     DBUG_VOID_RETURN;
   }
 
@@ -4153,6 +4173,8 @@ public:
     DBUG_PRINT("enter", ("m_incident: %d", m_incident));
     m_message= msg;
     set_direct_logging();
+    /* Replicate the incident irregardless of @@skip_replication. */
+    flags&= ~LOG_EVENT_SKIP_REPLICATION_F;
     DBUG_VOID_RETURN;
   }
 #endif
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 747374a41b788841a956065b6e9db4319b8f2d58..b290464a58898d915b328ede37a20c5f74bc6418 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -437,6 +437,8 @@ uint   opt_large_page_size= 0;
 MYSQL_PLUGIN_IMPORT uint    opt_debug_sync_timeout= 0;
 #endif /* defined(ENABLED_DEBUG_SYNC) */
 my_bool opt_old_style_user_limits= 0, trust_function_creators= 0;
+ulong opt_replicate_events_marked_for_skip;
+
 /*
   True if there is at least one per-hour limit for some user, so we should
   check them before each query (and possibly reset counters when hour is
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 296b747b1ce43da6d621c56c8749f16003573e05..db7857d9cd5547983620840ac4339dd8356662d1 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -109,6 +109,7 @@ extern my_bool opt_old_style_user_limits, trust_function_creators;
 extern uint opt_crash_binlog_innodb;
 extern char *shared_memory_base_name, *mysqld_unix_port;
 extern my_bool opt_enable_shared_memory;
+extern ulong opt_replicate_events_marked_for_skip;
 extern char *default_tz_name;
 extern Time_zone *default_tz;
 extern char *default_storage_engine;
diff --git a/sql/set_var.h b/sql/set_var.h
index d285787904c21eb195ab2ba05f67dfb929995961..c074f3f4399211cfc37269bcda72d072146e1d6a 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -171,6 +171,7 @@ protected:
 
 #include "sql_plugin.h"                    /* SHOW_HA_ROWS, SHOW_MY_BOOL */
 
+
 /****************************************************************************
   Classes for parsing of the SET command
 ****************************************************************************/
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 872e80ab5422e88261df041da7fa5df1b1c29c06..8e866c82123f1dad79bfb2bfa8da10aca7a076eb 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6557,4 +6557,7 @@ ER_CONNECTION_KILLED 70100
         eng "Connection was killed"
 ER_INTERNAL_ERROR
         eng "Internal error: '%-.192s'"
-
+ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION
+        eng "Cannot modify @@session.skip_replication inside a transaction"
+ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION
+        eng "Cannot modify @@session.skip_replication inside a stored function or trigger"
diff --git a/sql/slave.cc b/sql/slave.cc
index 2b73cad1d7b36f4955f49c62fa423a903b13a993..1e717a2e98c321b14e4bba1d7012d461bbbf16a1 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1710,6 +1710,48 @@ when it try to get the value of TIME_ZONE global variable from master.";
 past_checksum:
 #endif
 
+  /*
+    Request the master to filter away events with the @@skip_replication flag
+    set, if we are running with
+    --replicate-events-marked-for-skip=FILTER_ON_MASTER.
+  */
+  if (opt_replicate_events_marked_for_skip == RPL_SKIP_FILTER_ON_MASTER)
+  {
+    if (mysql_real_query(mysql, STRING_WITH_LEN("SET skip_replication=1")))
+    {
+      err_code= mysql_errno(mysql);
+      if (is_network_error(err_code))
+      {
+        mi->report(ERROR_LEVEL, err_code,
+                   "Setting master-side filtering of @@skip_replication failed "
+                   "with error: %s", mysql_error(mysql));
+        goto network_err;
+      }
+      else if (err_code == ER_UNKNOWN_SYSTEM_VARIABLE)
+      {
+        /*
+          The master is older than the slave and does not support the
+          @@skip_replication feature.
+          This is not a problem, as such master will not generate events with
+          the @@skip_replication flag set in the first place. We will still
+          do slave-side filtering of such events though, to handle the (rare)
+          case of downgrading a master and receiving old events generated from
+          before the downgrade with the @@skip_replication flag set.
+        */
+        DBUG_PRINT("info", ("Old master does not support master-side filtering "
+                            "of @@skip_replication events."));
+      }
+      else
+      {
+        /* Fatal error */
+        errmsg= "The slave I/O thread stops because a fatal error is "
+          "encountered when it tries to request filtering of events marked "
+          "with the @@skip_replication flag.";
+        sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql));
+        goto err;
+      }
+    }
+  }
 err:
   if (errmsg)
   {
@@ -2498,6 +2540,9 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli)
     ev->when= hrtime_to_my_time(hrtime);
     ev->when_sec_part= hrtime_sec_part(hrtime);
   }
+  thd->variables.option_bits=
+    (thd->variables.option_bits & ~OPTION_SKIP_REPLICATION) |
+    (ev->flags & LOG_EVENT_SKIP_REPLICATION_F ? OPTION_SKIP_REPLICATION : 0);
   ev->thd = thd; // because up to this point, ev->thd == 0
 
   int reason= ev->shall_skip(rli);
@@ -4062,6 +4107,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
   int error= 0;
   String error_msg;
   ulong inc_pos;
+  ulong event_pos;
   Relay_log_info *rli= &mi->rli;
   mysql_mutex_t *log_lock= rli->relay_log.get_log_lock();
   ulong s_id;
@@ -4134,7 +4180,6 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
       (uchar)buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT /* a way to escape */)
     DBUG_RETURN(queue_old_event(mi,buf,event_len));
 
-  LINT_INIT(inc_pos);
   mysql_mutex_lock(&mi->data_lock);
 
   switch ((uchar)buf[EVENT_TYPE_OFFSET]) {
@@ -4326,6 +4371,23 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
     break;
   }
 
+  /*
+    If we filter events master-side (eg. @@skip_replication), we will see holes
+    in the event positions from the master. If we see such a hole, adjust
+    mi->master_log_pos accordingly so we maintain the correct position (for
+    reconnect, MASTER_POS_WAIT(), etc.)
+  */
+  if (inc_pos > 0 &&
+      event_len >= LOG_POS_OFFSET+4 &&
+      (event_pos= uint4korr(buf+LOG_POS_OFFSET)) > mi->master_log_pos + inc_pos)
+  {
+    inc_pos= event_pos - mi->master_log_pos;
+    DBUG_PRINT("info", ("Adjust master_log_pos %lu->%lu to account for "
+                        "master-side filtering",
+                        (unsigned long)(mi->master_log_pos + inc_pos),
+                        event_pos));
+  }
+
   /*
      If this event is originating from this server, don't queue it.
      We don't check this for 3.23 events because it's simpler like this; 3.23
diff --git a/sql/slave.h b/sql/slave.h
index e519a9fc3fa1d09752d65b538d405c69d81a072c..6b4bcffe10941424d531898a21203aa38d00778d 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -152,6 +152,15 @@ extern ulonglong relay_log_space_limit;
 */
 #define SLAVE_FORCE_ALL 4
 
+/*
+  Values for the option --replicate-events-marked-for-skip.
+  Must match the names in replicate_events_marked_for_skip_names in sys_vars.cc
+*/
+#define RPL_SKIP_REPLICATE 0
+#define RPL_SKIP_FILTER_ON_SLAVE 1
+#define RPL_SKIP_FILTER_ON_MASTER 2
+
+
 int init_slave();
 int init_recovery(Master_info* mi, const char** errmsg);
 void init_slave_skip_errors(const char* arg);
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index 664590c34acc8e6c94641af46c7f884f0361261f..0ac92859365690446bd49b12dbaf39c8b6c9ebef 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -44,6 +44,7 @@
 
 void mysql_client_binlog_statement(THD* thd)
 {
+  ulonglong save_skip_replication;
   DBUG_ENTER("mysql_client_binlog_statement");
   DBUG_PRINT("info",("binlog base64: '%*s'",
                      (int) (thd->lex->comment.length < 2048 ?
@@ -225,7 +226,17 @@ void mysql_client_binlog_statement(THD* thd)
         reporting.
       */
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+      save_skip_replication= thd->variables.option_bits&OPTION_SKIP_REPLICATION;
+      thd->variables.option_bits=
+        (thd->variables.option_bits & ~OPTION_SKIP_REPLICATION) |
+        (ev->flags & LOG_EVENT_SKIP_REPLICATION_F ?
+         OPTION_SKIP_REPLICATION : 0);
+
       err= ev->apply_event(rli);
+
+      thd->variables.option_bits=
+        (thd->variables.option_bits & ~OPTION_SKIP_REPLICATION) |
+        save_skip_replication;
 #else
       err= 0;
 #endif
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index b9017f1e5ab7cad60a33d28a69ffda9482e2ba7b..78e1fed83fcc430ff3c798e2a965f5e22f0cc9b4 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -151,6 +151,7 @@
   Note! Reserved for use in MySQL Cluster
 */
 #define OPTION_ALLOW_BATCH              (ULL(1) << 36) // THD, intern (slave)
+#define OPTION_SKIP_REPLICATION         (ULL(1) << 37) // THD, user
 
 /* The rest of the file is included in the server only */
 #ifndef MYSQL_CLIENT
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 9974c56f3d16664ec2fc471e0e4695162c4e3c8d..29ab8b1d05b668916f0f82f08874ff55561e9808 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -556,8 +556,60 @@ static int send_heartbeat_event(NET* net, String* packet,
 
 
 /*
-  TODO: Clean up loop to only have one call to send_file()
+  Helper function for mysql_binlog_send() to write an event down the slave
+  connection.
+
+  Returns NULL on success, error message string on error.
 */
+static const char *
+send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags,
+                    Log_event_type event_type, char *log_file_name,
+                    IO_CACHE *log)
+{
+  my_off_t pos;
+
+  /* Do not send annotate_rows events unless slave requested it. */
+  if (event_type == ANNOTATE_ROWS_EVENT &&
+      !(flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT))
+    return NULL;
+
+  /*
+    Skip events with the @@skip_replication flag set, if slave requested
+    skipping of such events.
+  */
+  if (thd->variables.option_bits & OPTION_SKIP_REPLICATION)
+  {
+    /*
+      The first byte of the packet is a '\0' to distinguish it from an error
+      packet. So the actual event starts at offset +1.
+    */
+    uint16 event_flags= uint2korr(&((*packet)[FLAGS_OFFSET+1]));
+    if (event_flags & LOG_EVENT_SKIP_REPLICATION_F)
+      return NULL;
+  }
+
+  thd_proc_info(thd, "Sending binlog event to slave");
+
+  pos= my_b_tell(log);
+  if (RUN_HOOK(binlog_transmit, before_send_event,
+               (thd, flags, packet, log_file_name, pos)))
+    return "run 'before_send_event' hook failed";
+
+  if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
+    return "Failed on my_net_write()";
+
+  DBUG_PRINT("info", ("log event code %d", (*packet)[LOG_EVENT_OFFSET+1] ));
+  if (event_type == LOAD_EVENT)
+  {
+    if (send_file(thd))
+      return "failed in send_file()";
+  }
+
+  if (RUN_HOOK(binlog_transmit, after_send_event, (thd, flags, packet)))
+    return "Failed to run hook 'after_send_event'";
+
+  return NULL;    /* Success */
+}
 
 void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
 		       ushort flags)
@@ -570,9 +622,9 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
 
   IO_CACHE log;
   File file = -1;
-  String* packet = &thd->packet;
+  String* const packet = &thd->packet;
   int error;
-  const char *errmsg = "Unknown error";
+  const char *errmsg = "Unknown error", *tmp_msg;
   const char *fmt= "%s; the last event was read from '%s' at %s, the last byte read was read from '%s' at %s.";
   char llbuff1[22], llbuff2[22];
   char error_text[MAX_SLAVE_ERRMSG]; // to be send to slave via my_message()
@@ -889,51 +941,21 @@ impossible position";
         (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F;
       }
 
-      if (event_type != ANNOTATE_ROWS_EVENT ||
-          (flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT))
+      if ((tmp_msg= send_event_to_slave(thd, net, packet, flags, event_type,
+                                        log_file_name, &log)))
       {
-        pos = my_b_tell(&log);
-        if (RUN_HOOK(binlog_transmit, before_send_event,
-                     (thd, flags, packet, log_file_name, pos)))
-        {
-          my_errno= ER_UNKNOWN_ERROR;
-          errmsg= "run 'before_send_event' hook failed";
-          goto err;
-        }
-
-        if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
-        {
-          errmsg = "Failed on my_net_write()";
-          my_errno= ER_UNKNOWN_ERROR;
-          goto err;
-        }
+        errmsg= tmp_msg;
+        my_errno= ER_UNKNOWN_ERROR;
+        goto err;
+      }
 
-        DBUG_EXECUTE_IF("dump_thread_wait_before_send_xid",
+      DBUG_EXECUTE_IF("dump_thread_wait_before_send_xid",
+                      {
+                        if (event_type == XID_EVENT)
                         {
-                          if (event_type == XID_EVENT)
-                          {
-                            net_flush(net);
-                          }
-                        });
-
-        DBUG_PRINT("info", ("log event code %d", event_type));
-        if (event_type == LOAD_EVENT)
-        {
-          if (send_file(thd))
-          {
-            errmsg = "failed in send_file()";
-            my_errno= ER_UNKNOWN_ERROR;
-            goto err;
-          }
-        }
-
-        if (RUN_HOOK(binlog_transmit, after_send_event, (thd, flags, packet)))
-        {
-          errmsg= "Failed to run hook 'after_send_event'";
-          my_errno= ER_UNKNOWN_ERROR;
-          goto err;
-        }
-      }
+                          net_flush(net);
+                        }
+                      });
 
       /* reset transmit packet for next loop */
       if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
@@ -1078,43 +1100,13 @@ impossible position";
           goto err;
 	}
 
-	if (read_packet &&
-            (event_type != ANNOTATE_ROWS_EVENT ||
-             (flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)))
+        if (read_packet &&
+            (tmp_msg= send_event_to_slave(thd, net, packet, flags, event_type,
+                                          log_file_name, &log)))
         {
-          thd_proc_info(thd, "Sending binlog event to slave");
-          pos = my_b_tell(&log);
-          if (RUN_HOOK(binlog_transmit, before_send_event,
-                       (thd, flags, packet, log_file_name, pos)))
-          {
-            my_errno= ER_UNKNOWN_ERROR;
-            errmsg= "run 'before_send_event' hook failed";
-            goto err;
-          }
-	  
-	  if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) )
-	  {
-	    errmsg = "Failed on my_net_write()";
-	    my_errno= ER_UNKNOWN_ERROR;
-	    goto err;
-	  }
-
-	  if (event_type == LOAD_EVENT)
-	  {
-	    if (send_file(thd))
-	    {
-	      errmsg = "failed in send_file()";
-	      my_errno= ER_UNKNOWN_ERROR;
-	      goto err;
-	    }
-	  }
-
-          if (RUN_HOOK(binlog_transmit, after_send_event, (thd, flags, packet)))
-          {
-            my_errno= ER_UNKNOWN_ERROR;
-            errmsg= "Failed to run hook 'after_send_event'";
-            goto err;
-          }
+          errmsg= tmp_msg;
+          my_errno= ER_UNKNOWN_ERROR;
+          goto err;
 	}
 
 	log.error=0;
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 0e7344762422b82025a1acf80d00f18dc9059c51..9779f36b3a2010e1c0b603f24a7492aca987beed 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -231,6 +231,35 @@ static Sys_var_ulonglong Sys_binlog_stmt_cache_size(
        CMD_LINE(REQUIRED_ARG),
        VALID_RANGE(IO_SIZE, ULONGLONG_MAX), DEFAULT(32768), BLOCK_SIZE(IO_SIZE));
 
+/*
+  Some variables like @sql_log_bin and @binlog_format change how/if binlogging
+  is done. We must not change them inside a running transaction or statement,
+  otherwise the event group eventually written to the binlog may become
+  incomplete or otherwise garbled.
+
+  This function does the appropriate check.
+
+  It returns true if an error is caused by incorrect usage, false if ok.
+*/
+static bool
+error_if_in_trans_or_substatement(THD *thd, int in_substatement_error,
+                                  int in_transaction_error)
+{
+  if (thd->in_sub_stmt)
+  {
+    my_error(in_substatement_error, MYF(0));
+    return true;
+  }
+
+  if (thd->in_active_multi_stmt_transaction())
+  {
+    my_error(in_transaction_error, MYF(0));
+    return true;
+  }
+
+  return false;
+}
+
 static bool check_has_super(sys_var *self, THD *thd, set_var *var)
 {
   DBUG_ASSERT(self->scope() != sys_var::GLOBAL);// don't abuse check_has_super()
@@ -271,22 +300,10 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var)
     return true;
   }
 
-  /*
-    if in a stored function/trigger, it's too late to change mode
-  */
-  if (thd->in_sub_stmt)
-  {
-    my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
+  if (error_if_in_trans_or_substatement(thd,
+         ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT,
+         ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT))
     return true;
-  }
-  /*
-    Make the session variable 'binlog_format' read-only inside a transaction.
-  */
-  if (thd->in_active_multi_stmt_transaction())
-  {
-    my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
-    return true;
-  }
 
   return false;
 }
@@ -322,24 +339,10 @@ static bool binlog_direct_check(sys_var *self, THD *thd, set_var *var)
   if (var->type == OPT_GLOBAL)
     return false;
 
-   /*
-     Makes the session variable 'binlog_direct_non_transactional_updates'
-     read-only if within a procedure, trigger or function.
-   */
-   if (thd->in_sub_stmt)
-   {
-     my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0));
-     return true;
-   }
-   /*
-     Makes the session variable 'binlog_direct_non_transactional_updates'
-     read-only inside a transaction.
-   */
-   if (thd->in_active_multi_stmt_transaction())
-   {
-     my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0));
+  if (error_if_in_trans_or_substatement(thd,
+          ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT,
+          ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT))
      return true;
-   }
 
   return false;
 }
@@ -2015,6 +2018,67 @@ static Sys_var_mybool Sys_master_verify_checksum(
        "SHOW BINLOG EVENTS",
        GLOBAL_VAR(opt_master_verify_checksum), CMD_LINE(OPT_ARG),
        DEFAULT(FALSE));
+
+/* These names must match RPL_SKIP_XXX #defines in slave.h. */
+static const char *replicate_events_marked_for_skip_names[]= {
+  "replicate", "filter_on_slave", "filter_on_master", 0
+};
+static bool
+replicate_events_marked_for_skip_check(sys_var *self, THD *thd,
+                                                set_var *var)
+{
+  int thread_mask;
+  DBUG_ENTER("sys_var_replicate_events_marked_for_skip_check");
+
+  /* Slave threads must be stopped to change the variable. */
+  mysql_mutex_lock(&LOCK_active_mi);
+  lock_slave_threads(active_mi);
+  init_thread_mask(&thread_mask, active_mi, 0 /*not inverse*/);
+  unlock_slave_threads(active_mi);
+  mysql_mutex_unlock(&LOCK_active_mi);
+
+  if (thread_mask) // We refuse if any slave thread is running
+  {
+    my_error(ER_SLAVE_MUST_STOP, MYF(0));
+    DBUG_RETURN(true);
+  }
+  DBUG_RETURN(false);
+}
+bool
+Sys_var_replicate_events_marked_for_skip::global_update(THD *thd, set_var *var)
+{
+  bool result;
+  int thread_mask;
+  DBUG_ENTER("Sys_var_replicate_events_marked_for_skip::global_update");
+
+  /* Slave threads must be stopped to change the variable. */
+  mysql_mutex_lock(&LOCK_active_mi);
+  lock_slave_threads(active_mi);
+  init_thread_mask(&thread_mask, active_mi, 0 /*not inverse*/);
+  if (thread_mask) // We refuse if any slave thread is running
+  {
+    my_error(ER_SLAVE_MUST_STOP, MYF(0));
+    result= true;
+  }
+  else
+    result= Sys_var_enum::global_update(thd, var);
+
+  unlock_slave_threads(active_mi);
+  mysql_mutex_unlock(&LOCK_active_mi);
+  DBUG_RETURN(result);
+}
+static Sys_var_replicate_events_marked_for_skip Replicate_events_marked_for_skip
+   ("replicate_events_marked_for_skip",
+   "Whether the slave should replicate events that were created with "
+   "@@skip_replication=1 on the master. Default REPLICATE (no events are "
+   "skipped). Other values are FILTER_ON_SLAVE (events will be sent by the "
+   "master but ignored by the slave) and FILTER_ON_MASTER (events marked with "
+   "@@skip_replication=1 will be filtered on the master and never be sent to "
+   "the slave).",
+   GLOBAL_VAR(opt_replicate_events_marked_for_skip), CMD_LINE(REQUIRED_ARG),
+   replicate_events_marked_for_skip_names, DEFAULT(RPL_SKIP_REPLICATE),
+   NO_MUTEX_GUARD, NOT_IN_BINLOG,
+   ON_CHECK(replicate_events_marked_for_skip_check));
 #endif
 
 
@@ -2569,18 +2633,10 @@ static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var)
   if (var->type == OPT_GLOBAL)
     return FALSE;
 
-  /* If in a stored function/trigger, it's too late to change sql_log_bin. */
-  if (thd->in_sub_stmt)
-  {
-    my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN, MYF(0));
+  if (error_if_in_trans_or_substatement(thd,
+          ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN,
+          ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN))
     return TRUE;
-  }
-  /* Make the session variable 'sql_log_bin' read-only inside a transaction. */
-  if (thd->in_active_multi_stmt_transaction())
-  {
-    my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN, MYF(0));
-    return TRUE;
-  }
 
   return FALSE;
 }
@@ -2645,6 +2701,40 @@ static Sys_var_ulong Sys_profiling_history_size(
        VALID_RANGE(0, 100), DEFAULT(15), BLOCK_SIZE(1));
 #endif
 
+/*
+  When this is set by a connection, binlogged events will be marked with a
+  corresponding flag. The slave can be configured to not replicate events
+  so marked.
+  In the binlog dump thread on the master, this variable is re-used for a
+  related purpose: The slave sets this flag when connecting to the master to
+  request that the master filter out (ie. not send) any events with the flag
+  set, thus saving network traffic on events that would be ignored by the
+  slave anyway.
+*/
+static bool check_skip_replication(sys_var *self, THD *thd, set_var *var)
+{
+  /*
+    We must not change @@skip_replication in the middle of a transaction or
+    statement, as that could result in only part of the transaction / statement
+    being replicated.
+    (This would be particularly serious if we were to replicate eg.
+    Rows_log_event without Table_map_log_event or transactional updates without
+    the COMMIT).
+  */
+  if (error_if_in_trans_or_substatement(thd,
+          ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION,
+          ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION))
+    return 1;
+
+  return 0;
+}
+
+static Sys_var_bit Sys_skip_replication(
+       "skip_replication", "skip_replication",
+       SESSION_ONLY(option_bits), NO_CMD_LINE, OPTION_SKIP_REPLICATION,
+       DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+       ON_CHECK(check_skip_replication));
+
 static Sys_var_harows Sys_select_limit(
        "sql_select_limit",
        "The maximum number of rows to return from SELECT statements",
@@ -3521,7 +3611,7 @@ static Sys_var_mybool Sys_query_cache_strip_comments(
 
 static ulonglong in_transaction(THD *thd)
 {
-  return test(thd->server_status & SERVER_STATUS_IN_TRANS);
+  return test(thd->in_active_multi_stmt_transaction());
 }
 static Sys_var_session_special Sys_in_transaction(
        "in_transaction", "Whether there is an active transaction",
diff --git a/sql/sys_vars.h b/sql/sys_vars.h
index 272506ff1b5df09f0ea533ee9f45987bfdb6a546..f2a2966e6a28fc7832c195ea5c0f576fe7e68901 100644
--- a/sql/sys_vars.h
+++ b/sql/sys_vars.h
@@ -1800,6 +1800,26 @@ public:
   }
 };
 
+/*
+  Class for replicate_events_marked_for_skip.
+  We need a custom update function that ensures the slave is stopped when
+  the update is happening.
+*/
+class Sys_var_replicate_events_marked_for_skip: public Sys_var_enum
+{
+public:
+  Sys_var_replicate_events_marked_for_skip(const char *name_arg,
+          const char *comment, int flag_args, ptrdiff_t off, size_t size,
+          CMD_LINE getopt,
+          const char *values[], uint def_val, PolyLock *lock,
+          enum binlog_status_enum binlog_status_arg,
+          on_check_function on_check_func)
+    :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
+                  values, def_val, lock, binlog_status_arg, on_check_func)
+  {}
+  bool global_update(THD *thd, set_var *var);
+};
+
 /****************************************************************************
   Used templates
 ****************************************************************************/