diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test
index 48d9b859c2607b40d126a63e6e712cd448c69ef5..834edcff474103f1f3ad9920da78b839f11d8bfa 100644
--- a/mysql-test/extra/binlog_tests/binlog.test
+++ b/mysql-test/extra/binlog_tests/binlog.test
@@ -67,6 +67,19 @@ create table if not exists t2 select * from t1;
 create temporary table tt1 (a int);
 create table if not exists t3 like tt1;
 
+# BUG#25091 (A DELETE statement to mysql database is not logged with
+# ROW mode format): Checking that some basic operations on tables in
+# the mysql database is replicated even when the current database is
+# 'mysql'.
+
+--disable_warnings
+USE mysql;
+INSERT INTO user SET host='localhost', user='@#@', password=password('Just a test');
+UPDATE user SET password=password('Another password') WHERE host='localhost' AND user='@#@';
+DELETE FROM user WHERE host='localhost' AND user='@#@';
+--enable_warnings
+
+use test;
 --replace_column 2 # 5 #
 --replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
 show binlog events from 102;
diff --git a/mysql-test/r/binlog_row_binlog.result b/mysql-test/r/binlog_row_binlog.result
index aee270bd7f6f15a509d497060e25f72582500946..769f23ea86c4c8cf530f01832ff5537255749b7a 100644
--- a/mysql-test/r/binlog_row_binlog.result
+++ b/mysql-test/r/binlog_row_binlog.result
@@ -249,6 +249,11 @@ create table t1 (a int);
 create table if not exists t2 select * from t1;
 create temporary table tt1 (a int);
 create table if not exists t3 like tt1;
+USE mysql;
+INSERT INTO user SET host='localhost', user='@#@', password=password('Just a test');
+UPDATE user SET password=password('Another password') WHERE host='localhost' AND user='@#@';
+DELETE FROM user WHERE host='localhost' AND user='@#@';
+use test;
 show binlog events from 102;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
 master-bin.000001	#	Query	1	#	use `test`; create table t1 (id tinyint auto_increment primary key)
@@ -262,6 +267,12 @@ master-bin.000001	#	Query	1	#	use `test`; CREATE TABLE IF NOT EXISTS `t2` (
 master-bin.000001	#	Query	1	#	use `test`; CREATE TABLE IF NOT EXISTS `t3` (
   `a` int(11) DEFAULT NULL
 )
+master-bin.000001	#	Table_map	1	#	table_id: # (mysql.user)
+master-bin.000001	#	Write_rows	1	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Table_map	1	#	table_id: # (mysql.user)
+master-bin.000001	#	Update_rows	1	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Table_map	1	#	table_id: # (mysql.user)
+master-bin.000001	#	Delete_rows	1	#	table_id: # flags: STMT_END_F
 drop table t1,t2,t3,tt1;
 create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
 set @@session.auto_increment_increment=1, @@session.auto_increment_offset=1;
@@ -281,6 +292,12 @@ master-bin.000001	#	Query	1	#	use `test`; CREATE TABLE IF NOT EXISTS `t2` (
 master-bin.000001	#	Query	1	#	use `test`; CREATE TABLE IF NOT EXISTS `t3` (
   `a` int(11) DEFAULT NULL
 )
+master-bin.000001	#	Table_map	1	#	table_id: # (mysql.user)
+master-bin.000001	#	Write_rows	1	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Table_map	1	#	table_id: # (mysql.user)
+master-bin.000001	#	Update_rows	1	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Table_map	1	#	table_id: # (mysql.user)
+master-bin.000001	#	Delete_rows	1	#	table_id: # flags: STMT_END_F
 master-bin.000001	#	Query	1	#	use `test`; DROP TABLE `t1`,`t2`,`t3` /* generated by server */
 master-bin.000001	#	Query	1	#	use `test`; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam
 master-bin.000001	#	Table_map	1	#	table_id: # (test.t1)
diff --git a/mysql-test/r/binlog_stm_binlog.result b/mysql-test/r/binlog_stm_binlog.result
index a9b3f69eceed415d71eb002195e1ee97caba1150..fb0453b5b686f3962947812e7d3294847c9515ae 100644
--- a/mysql-test/r/binlog_stm_binlog.result
+++ b/mysql-test/r/binlog_stm_binlog.result
@@ -159,6 +159,11 @@ create table t1 (a int);
 create table if not exists t2 select * from t1;
 create temporary table tt1 (a int);
 create table if not exists t3 like tt1;
+USE mysql;
+INSERT INTO user SET host='localhost', user='@#@', password=password('Just a test');
+UPDATE user SET password=password('Another password') WHERE host='localhost' AND user='@#@';
+DELETE FROM user WHERE host='localhost' AND user='@#@';
+use test;
 show binlog events from 102;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
 master-bin.000001	#	Query	1	#	use `test`; create table t1 (id tinyint auto_increment primary key)
@@ -169,6 +174,9 @@ master-bin.000001	#	Query	1	#	use `test`; create table t1 (a int)
 master-bin.000001	#	Query	1	#	use `test`; create table if not exists t2 select * from t1
 master-bin.000001	#	Query	1	#	use `test`; create temporary table tt1 (a int)
 master-bin.000001	#	Query	1	#	use `test`; create table if not exists t3 like tt1
+master-bin.000001	#	Query	1	#	use `mysql`; INSERT INTO user SET host='localhost', user='@#@', password=password('Just a test')
+master-bin.000001	#	Query	1	#	use `mysql`; UPDATE user SET password=password('Another password') WHERE host='localhost' AND user='@#@'
+master-bin.000001	#	Query	1	#	use `mysql`; DELETE FROM user WHERE host='localhost' AND user='@#@'
 drop table t1,t2,t3,tt1;
 create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
 set @@session.auto_increment_increment=1, @@session.auto_increment_offset=1;
@@ -185,6 +193,9 @@ master-bin.000001	#	Query	1	#	use `test`; create table t1 (a int)
 master-bin.000001	#	Query	1	#	use `test`; create table if not exists t2 select * from t1
 master-bin.000001	#	Query	1	#	use `test`; create temporary table tt1 (a int)
 master-bin.000001	#	Query	1	#	use `test`; create table if not exists t3 like tt1
+master-bin.000001	#	Query	1	#	use `mysql`; INSERT INTO user SET host='localhost', user='@#@', password=password('Just a test')
+master-bin.000001	#	Query	1	#	use `mysql`; UPDATE user SET password=password('Another password') WHERE host='localhost' AND user='@#@'
+master-bin.000001	#	Query	1	#	use `mysql`; DELETE FROM user WHERE host='localhost' AND user='@#@'
 master-bin.000001	#	Query	1	#	use `test`; drop table t1,t2,t3,tt1
 master-bin.000001	#	Query	1	#	use `test`; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam
 master-bin.000001	#	Table_map	1	#	table_id: # (test.t1)
diff --git a/sql/handler.cc b/sql/handler.cc
index 360d528f0ad3baf875a7f4b3941f6c130a48060b..24cf5afb5c70313eb265d0d19ee554ab11ef7346 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -3481,7 +3481,7 @@ namespace {
     {
       int const check(table->s->tmp_table == NO_TMP_TABLE &&
                       binlog_filter->db_ok(table->s->db.str) &&
-                      strcmp("mysql", table->s->db.str) != 0);
+                      !table->no_replicate);
       table->s->cached_row_logging_check= check;
     }
 
diff --git a/sql/log.cc b/sql/log.cc
index 1b432ca15c0832666f244f3d1c778fe6787f161e..99431304b9637fdecc52924206a752fde131d99f 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -312,6 +312,7 @@ bool Log_to_csv_event_handler::open_log_table(uint log_table_type)
   {
     table->table->use_all_columns();
     table->table->locked_by_logger= TRUE;
+    table->table->no_replicate= TRUE;
   }
   /* restore thread settings */
   if (curr)
diff --git a/sql/sp.cc b/sql/sp.cc
index 14703e3aa424bfe97cdc57e375b2545f2553e038..b2bb165417625497360be455667ebb99d796c1da 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -500,6 +500,13 @@ db_create_routine(THD *thd, int type, sp_head *sp)
   DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length,
                        sp->m_name.str));
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
   if (!(table= open_proc_table_for_update(thd)))
     ret= SP_OPEN_TABLE_FAILED;
   else
@@ -636,6 +643,13 @@ db_drop_routine(THD *thd, int type, sp_name *name)
   DBUG_PRINT("enter", ("type: %d name: %.*s",
 		       type, name->m_name.length, name->m_name.str));
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
   if (!(table= open_proc_table_for_update(thd)))
     DBUG_RETURN(SP_OPEN_TABLE_FAILED);
   if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
@@ -668,6 +682,13 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
   DBUG_PRINT("enter", ("type: %d name: %.*s",
 		       type, name->m_name.length, name->m_name.str));
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
   if (!(table= open_proc_table_for_update(thd)))
     DBUG_RETURN(SP_OPEN_TABLE_FAILED);
   if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 0d9653172e021e3c2812cff0bb0357c68da4d5bb..bec632889c19e281467029b74b2f30d97241ead3 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3001,6 +3001,13 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
   tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
   tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
 #ifdef HAVE_REPLICATION
   /*
     GRANT and REVOKE are applied the slave in/exclusion rules as they are
@@ -3218,6 +3225,13 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
   tables[0].lock_type=tables[1].lock_type=TL_WRITE;
   tables[0].db=tables[1].db=(char*) "mysql";
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
 #ifdef HAVE_REPLICATION
   /*
     GRANT and REVOKE are applied the slave in/exclusion rules as they are
@@ -3357,6 +3371,13 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
   tables[0].lock_type=tables[1].lock_type=TL_WRITE;
   tables[0].db=tables[1].db=(char*) "mysql";
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
 #ifdef HAVE_REPLICATION
   /*
     GRANT and REVOKE are applied the slave in/exclusion rules as they are
@@ -5399,6 +5420,13 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
   TABLE_LIST tables[GRANT_TABLES];
   DBUG_ENTER("mysql_create_user");
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
   /* CREATE USER may be skipped on replication client. */
   if ((result= open_grant_tables(thd, tables)))
     DBUG_RETURN(result != 1);
@@ -5471,6 +5499,13 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
   TABLE_LIST tables[GRANT_TABLES];
   DBUG_ENTER("mysql_drop_user");
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
   /* DROP USER may be skipped on replication client. */
   if ((result= open_grant_tables(thd, tables)))
     DBUG_RETURN(result != 1);
@@ -5535,6 +5570,13 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
   TABLE_LIST tables[GRANT_TABLES];
   DBUG_ENTER("mysql_rename_user");
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
   /* RENAME USER may be skipped on replication client. */
   if ((result= open_grant_tables(thd, tables)))
     DBUG_RETURN(result != 1);
@@ -5610,6 +5652,13 @@ bool mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
   TABLE_LIST tables[GRANT_TABLES];
   DBUG_ENTER("mysql_revoke_all");
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
   if ((result= open_grant_tables(thd, tables)))
     DBUG_RETURN(result != 1);
 
@@ -5800,6 +5849,13 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
   rw_wrlock(&LOCK_grant);
   VOID(pthread_mutex_lock(&acl_cache->lock));
 
+  /*
+    This statement will be replicated as a statement, even when using
+    row-based replication.  The flag will be reset at the end of the
+    statement.
+  */
+  thd->clear_current_stmt_binlog_row_based();
+
   /* Remove procedure access */
   do
   {
diff --git a/sql/table.h b/sql/table.h
index 80add0e0b91bfa4cdc5c4b4264b8f712a1e2ccdc..7fd2b4050732c0f362ee1e715a518f0bbbe96ca4 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -389,6 +389,10 @@ struct st_table {
   /*
     If true, the current table row is considered to have all columns set to 
     NULL, including columns declared as "not null" (see maybe_null).
+
+    TODO: Each of these flags take up 8 bits. They can just as easily
+    be put into one single unsigned long and instead of taking up 18
+    bytes, it would take up 4.
   */
   my_bool null_row;
   my_bool force_index;
@@ -396,6 +400,7 @@ struct st_table {
   my_bool key_read, no_keyread;
   my_bool locked_by_flush;
   my_bool locked_by_logger;
+  my_bool no_replicate;
   my_bool locked_by_name;
   my_bool fulltext_searched;
   my_bool no_cache;