diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index eff53f4a7896cc97287b586ea7b1fc5d21674f9c..46814ec8517e9f049a62bc799865ad7affa3dce5 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -48,6 +48,7 @@ dlenev@build.mysql.com
 dlenev@jabberwock.localdomain
 dlenev@mysql.com
 ejonore@mc03.ndb.mysql.com
+gbichot@production.mysql.com
 gbichot@quadita2.mysql.com
 georg@beethoven.local
 georg@beethoven.site
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index c296447def9df9e53faa41e9e73da2b15417a5a4..59c90f59e8ed8f8b5c7745cf0c0f7a3c857339dc 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -33,9 +33,9 @@
 #undef MYSQL_SERVER
 #include "client_priv.h"
 #include <my_time.h>
-#include "log_event.h"
 /* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
 #include "mysql_priv.h" 
+#include "log_event.h"
 
 #define BIN_LOG_HEADER_SIZE	4
 #define PROBE_HEADER_LEN	(EVENT_LEN_OFFSET+4)
diff --git a/mysql-test/r/rpl_timezone.result b/mysql-test/r/rpl_timezone.result
index cd2c4d099bee72caadac7c418c68dc60aa303fbb..8975333d1dba18b5eb007023671882da09407c6a 100644
--- a/mysql-test/r/rpl_timezone.result
+++ b/mysql-test/r/rpl_timezone.result
@@ -4,21 +4,31 @@ reset master;
 reset slave;
 drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
 start slave;
+set timestamp=100000000;
 create table t1 (t timestamp);
 create table t2 (t char(32));
 select @@time_zone;
 @@time_zone
+Japan
+select @@time_zone;
+@@time_zone
 Europe/Moscow
+insert into t1 values ('20050101000000'), ('20050611093902');
 set time_zone='UTC';
 insert into t1 values ('20040101000000'), ('20040611093902');
 select * from t1;
 t
+2004-12-31 21:00:00
+2005-06-11 05:39:02
 2004-01-01 00:00:00
 2004-06-11 09:39:02
+set time_zone='UTC';
 select * from t1;
 t
-2004-01-01 03:00:00
-2004-06-11 13:39:02
+2004-12-31 21:00:00
+2005-06-11 05:39:02
+2004-01-01 00:00:00
+2004-06-11 09:39:02
 delete from t1;
 set time_zone='Europe/Moscow';
 insert into t1 values ('20040101000000'), ('20040611093902');
@@ -26,19 +36,35 @@ select * from t1;
 t
 2004-01-01 00:00:00
 2004-06-11 09:39:02
+set time_zone='Europe/Moscow';
 select * from t1;
 t
 2004-01-01 00:00:00
 2004-06-11 09:39:02
-show binlog events;
-Log_name	Pos	Event_type	Server_id	End_log_pos	Info
-master-bin.000001	#	Format_desc	1	#	Server ver: VERSION, Binlog ver: 4
-master-bin.000001	#	Query	1	#	use `test`; create table t1 (t timestamp)
-master-bin.000001	#	Query	1	#	use `test`; create table t2 (t char(32))
-master-bin.000001	#	Query	1	#	use `test`; SET ONE_SHOT TIME_ZONE='UTC'
-master-bin.000001	#	Query	1	#	use `test`; insert into t1 values ('20040101000000'), ('20040611093902')
-master-bin.000001	#	Query	1	#	use `test`; delete from t1
-master-bin.000001	#	Query	1	#	use `test`; insert into t1 values ('20040101000000'), ('20040611093902')
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+ROLLBACK;
+use test;
+SET TIMESTAMP=100000000;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
+SET @@session.sql_mode=0;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
+create table t1 (t timestamp);
+SET TIMESTAMP=100000000;
+create table t2 (t char(32));
+SET TIMESTAMP=100000000;
+SET @@session.time_zone='Europe/Moscow';
+insert into t1 values ('20050101000000'), ('20050611093902');
+SET TIMESTAMP=100000000;
+SET @@session.time_zone='UTC';
+insert into t1 values ('20040101000000'), ('20040611093902');
+SET TIMESTAMP=100000000;
+delete from t1;
+SET TIMESTAMP=100000000;
+SET @@session.time_zone='Europe/Moscow';
+insert into t1 values ('20040101000000'), ('20040611093902');
+ROLLBACK;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
 set time_zone='MET';
 insert into t2 (select t from t1);
 select * from t1;
@@ -52,10 +78,6 @@ t
 delete from t2;
 set timestamp=1000072000;
 insert into t2 values (current_timestamp), (current_date), (current_time);
-set timestamp=1000072000;
-select current_timestamp, current_date, current_time;
-current_timestamp	current_date	current_time
-2001-09-10 01:46:40	2001-09-10	01:46:40
 select * from t2;
 t
 2001-09-09 23:46:40
@@ -73,5 +95,16 @@ t
 2001-09-09 03:46:40
 1000000000
 set global time_zone='MET';
-ERROR HY000: Binary logging and replication forbid changing the global server time zone
+delete from t2;
+set time_zone='UTC';
+insert into t2 values(convert_tz('2004-01-01 00:00:00','MET',@@time_zone));
+insert into t2 values(convert_tz('2005-01-01 00:00:00','MET','Japan'));
+select * from t2;
+t
+2003-12-31 23:00:00
+2005-01-01 08:00:00
+select * from t2;
+t
+2003-12-31 23:00:00
+2005-01-01 08:00:00
 drop table t1, t2;
diff --git a/mysql-test/t/rpl_timezone-slave.opt b/mysql-test/t/rpl_timezone-slave.opt
index 8e43bfbbb7e429c7b79ece74f3a64d8046d8aa4a..191182c329cb6756d599064b2a37504a3a66f151 100644
--- a/mysql-test/t/rpl_timezone-slave.opt
+++ b/mysql-test/t/rpl_timezone-slave.opt
@@ -1 +1 @@
---default-time-zone=Europe/Moscow
+--default-time-zone=Japan
diff --git a/mysql-test/t/rpl_timezone.test b/mysql-test/t/rpl_timezone.test
index 3c180ca8849d25ecc61332e3c4845364c7f23b4c..a49cdd0acd26af534a0c7869c20c47e2e4cc612f 100644
--- a/mysql-test/t/rpl_timezone.test
+++ b/mysql-test/t/rpl_timezone.test
@@ -3,21 +3,25 @@ source include/master-slave.inc;
 
 # Some preparations
 let $VERSION=`select version()`;
+set timestamp=100000000; # for fixed output of mysqlbinlog
 create table t1 (t timestamp);
 create table t2 (t char(32));
 
+connection slave;
+select @@time_zone;
+
 #
 # Let us check how well replication works when we are saving datetime
 # value in TIMESTAMP field.
 #
 connection master;
 select @@time_zone;
+insert into t1 values ('20050101000000'), ('20050611093902');
 set time_zone='UTC';
 insert into t1 values ('20040101000000'), ('20040611093902');
 select * from t1;
-# On slave we still in 'Europe/Moscow' so we should see equivalent but
-# textually different values.
 sync_slave_with_master;
+set time_zone='UTC';
 select * from t1;
 
 # Let us check also that setting of time_zone back to default also works
@@ -28,12 +32,11 @@ set time_zone='Europe/Moscow';
 insert into t1 values ('20040101000000'), ('20040611093902');
 select * from t1;
 sync_slave_with_master;
+set time_zone='Europe/Moscow';
 select * from t1;
 connection master;
-# We should not see SET ONE_SHOT time_zone before second insert
---replace_result $VERSION VERSION
---replace_column 2 # 5 #
-show binlog events;
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001 
 
 #
 # Now let us check how well we replicate statments reading TIMESTAMP fields
@@ -54,10 +57,6 @@ delete from t2;
 set timestamp=1000072000;
 insert into t2 values (current_timestamp), (current_date), (current_time);
 sync_slave_with_master;
-# Values in ouput of these to queries should differ because we are in
-# in 'MET' on master and in 'Europe/Moscow on slave...
-set timestamp=1000072000;
-select current_timestamp, current_date, current_time;
 select * from t2;
 
 #
@@ -73,13 +72,24 @@ sync_slave_with_master;
 select * from t2;
 
 #
-# Let us check that we are not allowing to set global time_zone with
+# Let us check that we are allowing to set global time_zone with
 # replication
 #
 connection master;
---error 1387
 set global time_zone='MET';
 
+#
+# Let us see if CONVERT_TZ(@@time_zone) replicates
+#
+delete from t2;
+set time_zone='UTC';
+insert into t2 values(convert_tz('2004-01-01 00:00:00','MET',@@time_zone));
+insert into t2 values(convert_tz('2005-01-01 00:00:00','MET','Japan'));
+select * from t2;
+sync_slave_with_master;
+select * from t2;
+
 # Clean up
+connection master;
 drop table t1, t2;
 sync_slave_with_master;
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 870ad1af52b91295ce2efcc579879f9cba50bc3d..24f1579544ba87f1ca7cf44309653fac6e7d0c3c 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1307,6 +1307,9 @@ innobase_end(void)
 	}
 #endif
 	if (innodb_inited) {
+
+#ifndef __NETWARE__ 	/* NetWare can't close unclosed files, kill remaining
+                        threads, etc, so we disable the very fast shutdown */
 	  	if (innobase_very_fast_shutdown) {
 	    		srv_very_fast_shutdown = TRUE;
 	    		fprintf(stderr,
@@ -1314,6 +1317,7 @@ innobase_end(void)
 "InnoDB: the InnoDB buffer pool to data files. At the next mysqld startup\n"
 "InnoDB: InnoDB will do a crash recovery!\n");
 	  	}
+#endif
 
 	  	innodb_inited = 0;
 	  	if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
diff --git a/sql/log.cc b/sql/log.cc
index 43786990797d7c2289d3337a94b61352c6c5ae94..0c1d6836cce34c4fbd5ffb816a8497e505de43eb 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1638,57 +1638,6 @@ bool MYSQL_LOG::write(Log_event *event_info)
 
     if (thd)
     {
-#if MYSQL_VERSION_ID < 50003
-      /*
-        To make replication of charsets working in 4.1 we are writing values
-        of charset related variables before every statement in the binlog,
-        if values of those variables differ from global server-wide defaults.
-        We are using SET ONE_SHOT command so that the charset vars get reset
-        to default after the first non-SET statement.
-        In the next 5.0 this won't be needed as we will use the new binlog
-        format to store charset info.
-      */
-      if ((thd->variables.character_set_client->number !=
-           global_system_variables.collation_server->number) ||
-          (thd->variables.character_set_client->number !=
-           thd->variables.collation_connection->number) ||
-          (thd->variables.collation_server->number !=
-           thd->variables.collation_connection->number))
-      {
-	char buf[200];
-        int written= my_snprintf(buf, sizeof(buf)-1,
-                                 "SET ONE_SHOT CHARACTER_SET_CLIENT=%u,\
-COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
-                                 (uint) thd->variables.character_set_client->number,
-                                 (uint) thd->variables.collation_connection->number,
-                                 (uint) thd->variables.collation_database->number,
-                                 (uint) thd->variables.collation_server->number);
-	Query_log_event e(thd, buf, written, 0, FALSE);
-	if (e.write(file))
-	  goto err;
-      }
-#endif
-      /*
-        We use the same ONE_SHOT trick for making replication of time zones 
-        working in 4.1. Again in 5.0 we have better means for doing this.
-
-        TODO: we should do like we now do with charsets (no more ONE_SHOT;
-        logging in each event in a compact format). Dmitri says we can do:
-        if (time_zone_used) write the timezone to binlog (in a format to be
-        defined).
-      */
-      if (thd->time_zone_used &&
-          thd->variables.time_zone != global_system_variables.time_zone)
-      {
-        char buf[MAX_TIME_ZONE_NAME_LENGTH + 26];
-        char *buf_end= strxmov(buf, "SET ONE_SHOT TIME_ZONE='", 
-                               thd->variables.time_zone->get_name()->ptr(),
-                               "'", NullS);
-        Query_log_event e(thd, buf, buf_end - buf, 0, FALSE);
-        if (e.write(file))
-          goto err;
-      }
-
       if (thd->last_insert_id_used)
       {
 	Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
diff --git a/sql/log_event.cc b/sql/log_event.cc
index ba018e859c17158f2cd1e3a8143b1d55cb3c406a..666c2427ac5748f283f80b2625986c3fe521c05a 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -506,8 +506,6 @@ void Log_event::init_show_field_list(List<Item>* field_list)
   field_list->push_back(new Item_empty_string("Info", 20));
 }
 
-#endif /* !MYSQL_CLIENT */
-
 
 /*
   Log_event::write()
@@ -592,7 +590,6 @@ bool Log_event::write_header(IO_CACHE* file, ulong event_data_length)
 
 */
 
-#ifndef MYSQL_CLIENT
 int Log_event::read_log_event(IO_CACHE* file, String* packet,
 			      pthread_mutex_t* log_lock)
 {
@@ -956,6 +953,7 @@ void Query_log_event::pack_info(Protocol *protocol)
 }
 #endif
 
+#ifndef MYSQL_CLIENT
 
 /*
   Query_log_event::write()
@@ -973,7 +971,8 @@ bool Query_log_event::write(IO_CACHE* file)
             1+8+           // code of sql_mode and sql_mode
             1+1+FN_REFLEN+ // code of catalog and catalog length and catalog
             1+4+           // code of autoinc and the 2 autoinc variables
-            1+6            // code of charset and charset
+            1+6+           // code of charset and charset
+            1+1+MAX_TIME_ZONE_NAME_LENGTH // code of tz and tz length and tz name
             ], *start, *start_of_status;
   ulong event_length;
 
@@ -1030,20 +1029,20 @@ bool Query_log_event::write(IO_CACHE* file)
   start_of_status= start= buf+QUERY_HEADER_LEN;
   if (flags2_inited)
   {
-    *(start++)= Q_FLAGS2_CODE;
+    *start++= Q_FLAGS2_CODE;
     int4store(start, flags2);
     start+= 4;
   }
   if (sql_mode_inited)
   {
-    *(start++)= Q_SQL_MODE_CODE;
+    *start++= Q_SQL_MODE_CODE;
     int8store(start, (ulonglong)sql_mode);
     start+= 8;
   }
-  if (catalog_len >= 0) // i.e. "catalog inited" (false for 4.0 events)
+  if (catalog_len) // i.e. "catalog inited" (false for 4.0 events)
   {
-    *(start++)= Q_CATALOG_CODE;
-    *(start++)= (uchar) catalog_len;
+    *start++= Q_CATALOG_CODE;
+    *start++= (uchar) catalog_len;
     bmove(start, catalog, catalog_len);
     start+= catalog_len;
     /*
@@ -1071,15 +1070,24 @@ bool Query_log_event::write(IO_CACHE* file)
   }
   if (charset_inited)
   {
-    *(start++)= Q_CHARSET_CODE;
+    *start++= Q_CHARSET_CODE;
     memcpy(start, charset, 6);
     start+= 6;
   }
+  if (time_zone_len)
+  {
+    /* In the TZ sys table, column Name is of length 64 so this should be ok */
+    DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH);
+    *start++= Q_TIME_ZONE_CODE;
+    *start++= time_zone_len;
+    memcpy(start, time_zone_str, time_zone_len);
+    start+= time_zone_len;
+  }
   /*
     Here there could be code like
     if (command-line-option-which-says-"log_this_variable" && inited)
     {
-    *(start++)= Q_THIS_VARIABLE_CODE;
+    *start++= Q_THIS_VARIABLE_CODE;
     int4store(start, this_variable);
     start+= 4;
     }
@@ -1108,8 +1116,6 @@ bool Query_log_event::write(IO_CACHE* file)
 /*
   Query_log_event::Query_log_event()
 */
-
-#ifndef MYSQL_CLIENT
 Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
 				 ulong query_length, bool using_trans,
 				 bool suppress_use)
@@ -1150,6 +1156,18 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
   int2store(charset, thd_arg->variables.character_set_client->number);
   int2store(charset+2, thd_arg->variables.collation_connection->number);
   int2store(charset+4, thd_arg->variables.collation_server->number);
+  if (thd_arg->time_zone_used)
+  {
+    /*
+      Note that our event becomes dependent on the Time_zone object
+      representing the time zone. Fortunately such objects are never deleted
+      or changed during mysqld's lifetime.
+    */
+    time_zone_len= thd_arg->variables.time_zone->get_name()->length();
+    time_zone_str= thd_arg->variables.time_zone->get_name()->ptr();
+  }
+  else
+    time_zone_len= 0;
   DBUG_PRINT("info",("Query_log_event has flags2=%lu sql_mode=%lu",flags2,sql_mode));
 }
 #endif /* MYSQL_CLIENT */
@@ -1163,15 +1181,17 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
 Query_log_event::Query_log_event(const char* buf, uint event_len,
                                  const Format_description_log_event *description_event,
                                  Log_event_type event_type)
-  :Log_event(buf, description_event), data_buf(0), query(NullS), catalog(NullS), 
+  :Log_event(buf, description_event), data_buf(0), query(NullS),
    db(NullS), catalog_len(0), status_vars_len(0),
    flags2_inited(0), sql_mode_inited(0), charset_inited(0),
-   auto_increment_increment(1), auto_increment_offset(1)
+   auto_increment_increment(1), auto_increment_offset(1),
+   time_zone_len(0)
 {
   ulong data_len;
   uint32 tmp;
   uint8 common_header_len, post_header_len;
-  const char *start, *end;
+  char *start;
+  const char *end;
   DBUG_ENTER("Query_log_event::Query_log_event(char*,...)");
 
   common_header_len= description_event->common_header_len;
@@ -1191,7 +1211,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
   
   slave_proxy_id= thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET);
   exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET);
-  db_len = (uint)buf[Q_DB_LEN_OFFSET];
+  db_len = (uint)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars
   error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
 
   /*
@@ -1217,7 +1237,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
   /* variable-part: the status vars; only in MySQL 5.0  */
   
   start= (char*) (buf+post_header_len);
-  end= (char*) (start+status_vars_len);
+  end= (const char*) (start+status_vars_len);
   for (const uchar* pos= (const uchar*) start; pos < (const uchar*) end;)
   {
     switch (*pos++) {
@@ -1240,8 +1260,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
       break;
     }
     case Q_CATALOG_CODE:
-      catalog_len= *pos;
-      if (catalog_len)
+      if ((catalog_len= *pos))
         catalog= (char*) pos+1;                           // Will be copied later
       pos+= catalog_len+2;
       break;
@@ -1257,6 +1276,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
       pos+= 6;
       break;
     }
+    case Q_TIME_ZONE_CODE:
+    {
+      if ((time_zone_len= *pos))
+        time_zone_str= (char *)(pos+1);
+      pos+= time_zone_len+1;
+      break;
+    }
     default:
       /* That's why you must write status vars in growing order of code */
       DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\
@@ -1265,24 +1291,29 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
     }
   }
   
-  /* A 2nd variable part; this is common to all versions */ 
-  
-  if (!(start= data_buf = (char*) my_malloc(catalog_len + data_len +2, MYF(MY_WME))))
+  if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 +
+                                            time_zone_len + 1 +
+                                            data_len + 1, MYF(MY_WME))))
     DBUG_VOID_RETURN;
-  if (catalog)                                  // If catalog is given
+  if (catalog_len)                                  // If catalog is given
   {
-    memcpy((char*) start, catalog, catalog_len+1);      // Copy name and end \0
+    memcpy(start, catalog, catalog_len+1);      // Copy name and end \0
     catalog= start;
     start+= catalog_len+1;
   }
+  if (time_zone_len)
+  {
+    memcpy(start, time_zone_str, time_zone_len);
+    time_zone_str= start;
+    start+= time_zone_len;
+    *start++= 0;
+  }
+  /* A 2nd variable part; this is common to all versions */ 
   memcpy((char*) start, end, data_len);          // Copy db and query
-  ((char*) start)[data_len]= '\0';              // End query with \0 (For safetly)
+  start[data_len]= '\0';              // End query with \0 (For safetly)
   db= start;
   query= start + db_len + 1;
   q_len= data_len - db_len -1;
-  /* This is used to detect wrong parsing. Could be removed in the future. */
-  DBUG_PRINT("info", ("catalog: '%s'  len: %u   db: '%s'  len:  %u  q_len: %lu",
-                      catalog, (uint) catalog_len, db, (uint) db_len,q_len));
   DBUG_VOID_RETURN;
 }
 
@@ -1390,6 +1421,8 @@ void Query_log_event::print_query_header(FILE* file, bool short_form,
     last_event_info->auto_increment_offset=    auto_increment_offset;
   }
 
+  /* TODO: print the catalog when we feature SET CATALOG */
+
   if (likely(charset_inited))
   {
     if (unlikely(!last_event_info->charset_inited)) /* first Query event */
@@ -1410,6 +1443,14 @@ void Query_log_event::print_query_header(FILE* file, bool short_form,
       memcpy(last_event_info->charset, charset, 6);
     }
   }
+  if (time_zone_len)
+  {
+    if (bcmp(last_event_info->time_zone_str, time_zone_str, time_zone_len+1))
+    {
+      fprintf(file,"SET @@session.time_zone='%s';\n", time_zone_str);
+      memcpy(last_event_info->time_zone_str, time_zone_str, time_zone_len+1);
+    }
+  }
 }
 
 
@@ -1443,7 +1484,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query
     alloced block (see Query_log_event::exec_event()). Same for thd->db.
     Thank you.
   */
-  thd->catalog= (char*) catalog;
+  thd->catalog= catalog_len ? (char *) catalog : (char *)"";
   thd->db_length= db_len;
   thd->db= (char*) rewrite_db(db, &thd->db_length);
   thd->variables.auto_increment_increment= auto_increment_increment;
@@ -1513,20 +1554,28 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query
                 get_charset(uint2korr(charset+4), MYF(MY_WME))))
           {
             /*
-              We updated the thd->variables with nonsensical values (0), and the
-              thread is not guaranteed to terminate now (as it may be configured
-              to ignore EE_UNKNOWN_CHARSET);if we're going to execute a next
-              statement we'll have a new charset info with it, so no problem to
-              have stored 0 in thd->variables. But we invalidate cached
-              charset to force a check next time (otherwise if next time
-              charset is unknown again we won't detect it).
+              We updated the thd->variables with nonsensical values (0). Let's
+              set them to something safe (i.e. which avoids crash), and we'll
+              stop with EE_UNKNOWN_CHARSET in compare_errors (unless set to
+              ignore this error).
             */
-            rli->cached_charset_invalidate();
+            set_slave_thread_default_charset(thd, rli);
             goto compare_errors;
           }
           thd->update_charset(); // for the charset change to take effect
         }
       }
+      if (time_zone_len)
+      {
+        String tmp(time_zone_str, time_zone_len, &my_charset_bin);
+        if (!(thd->variables.time_zone=
+              my_tz_find_with_opening_tz_tables(thd, &tmp)))
+        {
+          my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr());
+          thd->variables.time_zone= global_system_variables.time_zone;
+          goto compare_errors;
+        }
+      }
 
       /* Execute the query (note that we bypass dispatch_command()) */
       mysql_parse(thd, thd->query, thd->query_length);
@@ -1751,6 +1800,7 @@ Start_log_event_v3::Start_log_event_v3(const char* buf,
   Start_log_event_v3::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Start_log_event_v3::write(IO_CACHE* file)
 {
   char buff[START_V3_HEADER_LEN];
@@ -1760,6 +1810,7 @@ bool Start_log_event_v3::write(IO_CACHE* file)
   return (write_header(file, sizeof(buff)) ||
           my_b_safe_write(file, (byte*) buff, sizeof(buff)));
 }
+#endif
 
 
 /*
@@ -1975,7 +2026,7 @@ Format_description_log_event(const char* buf,
   DBUG_VOID_RETURN;
 }
 
-
+#ifndef MYSQL_CLIENT
 bool Format_description_log_event::write(IO_CACHE* file)
 {
   /*
@@ -1992,6 +2043,7 @@ bool Format_description_log_event::write(IO_CACHE* file)
   return (write_header(file, sizeof(buff)) ||
           my_b_safe_write(file, buff, sizeof(buff)));
 }
+#endif
 
 /*
   SYNOPSIS
@@ -2208,6 +2260,8 @@ void Load_log_event::pack_info(Protocol *protocol)
 #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
 
 
+#ifndef MYSQL_CLIENT
+
 /*
   Load_log_event::write_data_header()
 */
@@ -2249,7 +2303,6 @@ bool Load_log_event::write_data_body(IO_CACHE* file)
   Load_log_event::Load_log_event()
 */
 
-#ifndef MYSQL_CLIENT
 Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
 			       const char *db_arg, const char *table_name_arg,
 			       List<Item> &fields_arg,
@@ -2863,6 +2916,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
   Rotate_log_event::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Rotate_log_event::write(IO_CACHE* file)
 {
   char buf[ROTATE_HEADER_LEN];
@@ -2871,7 +2925,7 @@ bool Rotate_log_event::write(IO_CACHE* file)
           my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
           my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
 }
-
+#endif
 
 /*
   Rotate_log_event::exec_event()
@@ -2929,17 +2983,10 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
       master is 4.0 then the events are in the slave's format (conversion).
     */
     set_slave_thread_options(thd);
+    set_slave_thread_default_charset(thd, rli);
     thd->variables.sql_mode= global_system_variables.sql_mode;
     thd->variables.auto_increment_increment=
       thd->variables.auto_increment_offset= 1;
-    thd->variables.character_set_client=
-      global_system_variables.character_set_client;
-    thd->variables.collation_connection=
-      global_system_variables.collation_connection;
-    thd->variables.collation_server=
-      global_system_variables.collation_server;
-    thd->update_charset();
-    rli->cached_charset_invalidate();
   }
   pthread_mutex_unlock(&rli->data_lock);
   pthread_cond_broadcast(&rli->data_cond);
@@ -3001,6 +3048,7 @@ const char* Intvar_log_event::get_var_type_name()
   Intvar_log_event::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Intvar_log_event::write(IO_CACHE* file)
 {
   byte buf[9];
@@ -3009,6 +3057,7 @@ bool Intvar_log_event::write(IO_CACHE* file)
   return (write_header(file, sizeof(buf)) ||
           my_b_safe_write(file, buf, sizeof(buf)));
 }
+#endif
 
 
 /*
@@ -3093,6 +3142,7 @@ Rand_log_event::Rand_log_event(const char* buf,
 }
 
 
+#ifndef MYSQL_CLIENT
 bool Rand_log_event::write(IO_CACHE* file)
 {
   byte buf[16];
@@ -3101,6 +3151,7 @@ bool Rand_log_event::write(IO_CACHE* file)
   return (write_header(file, sizeof(buf)) ||
           my_b_safe_write(file, buf, sizeof(buf)));
 }
+#endif
 
 
 #ifdef MYSQL_CLIENT
@@ -3164,11 +3215,13 @@ Xid_log_event(const char* buf,
 }
 
 
+#ifndef MYSQL_CLIENT
 bool Xid_log_event::write(IO_CACHE* file)
 {
   return write_header(file, sizeof(xid)) ||
          my_b_safe_write(file, (byte*) &xid, sizeof(xid));
 }
+#endif
 
 
 #ifdef MYSQL_CLIENT
@@ -3302,6 +3355,7 @@ User_var_log_event(const char* buf,
 }
 
 
+#ifndef MYSQL_CLIENT
 bool User_var_log_event::write(IO_CACHE* file)
 {
   char buf[UV_NAME_LEN_SIZE];
@@ -3361,6 +3415,7 @@ bool User_var_log_event::write(IO_CACHE* file)
 	  my_b_safe_write(file, (byte*) buf1, buf1_length) ||
 	  my_b_safe_write(file, (byte*) pos, val_len));
 }
+#endif
 
 
 /*
@@ -3634,6 +3689,7 @@ int Slave_log_event::get_data_size()
 }
 
 
+#ifndef MYSQL_CLIENT
 bool Slave_log_event::write(IO_CACHE* file)
 {
   ulong event_length= get_data_size();
@@ -3644,6 +3700,7 @@ bool Slave_log_event::write(IO_CACHE* file)
   return (write_header(file, event_length) ||
           my_b_safe_write(file, (byte*) mem_pool, event_length));
 }
+#endif
 
 
 void Slave_log_event::init_from_mem_pool(int data_size)
@@ -3770,7 +3827,6 @@ Create_file_log_event(THD* thd_arg, sql_exchange* ex,
   sql_ex.force_new_format();
   DBUG_VOID_RETURN;
 }
-#endif /* !MYSQL_CLIENT */
 
 
 /*
@@ -3815,6 +3871,7 @@ bool Create_file_log_event::write_base(IO_CACHE* file)
   return res;
 }
 
+#endif /* !MYSQL_CLIENT */
 
 /*
   Create_file_log_event ctor
@@ -4042,6 +4099,7 @@ Append_block_log_event::Append_block_log_event(const char* buf, uint len,
   Append_block_log_event::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Append_block_log_event::write(IO_CACHE* file)
 {
   byte buf[APPEND_BLOCK_HEADER_LEN];
@@ -4050,6 +4108,7 @@ bool Append_block_log_event::write(IO_CACHE* file)
           my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
 	  my_b_safe_write(file, (byte*) block, block_len));
 }
+#endif
 
 
 /*
@@ -4171,6 +4230,7 @@ Delete_file_log_event::Delete_file_log_event(const char* buf, uint len,
   Delete_file_log_event::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Delete_file_log_event::write(IO_CACHE* file)
 {
  byte buf[DELETE_FILE_HEADER_LEN];
@@ -4178,6 +4238,7 @@ bool Delete_file_log_event::write(IO_CACHE* file)
  return (write_header(file, sizeof(buf)) ||
          my_b_safe_write(file, buf, sizeof(buf)));
 }
+#endif
 
 
 /*
@@ -4265,6 +4326,7 @@ Execute_load_log_event::Execute_load_log_event(const char* buf, uint len,
   Execute_load_log_event::write()
 */
 
+#ifndef MYSQL_CLIENT
 bool Execute_load_log_event::write(IO_CACHE* file)
 {
   byte buf[EXEC_LOAD_HEADER_LEN];
@@ -4272,6 +4334,7 @@ bool Execute_load_log_event::write(IO_CACHE* file)
   return (write_header(file, sizeof(buf)) || 
           my_b_safe_write(file, buf, sizeof(buf)));
 }
+#endif
 
 
 /*
@@ -4475,6 +4538,7 @@ ulong Execute_load_query_log_event::get_post_header_size_for_derived()
 }
 
 
+#ifndef MYSQL_CLIENT
 bool
 Execute_load_query_log_event::write_post_header_for_derived(IO_CACHE* file)
 {
@@ -4485,6 +4549,7 @@ Execute_load_query_log_event::write_post_header_for_derived(IO_CACHE* file)
   *(buf + 4 + 4 + 4)= (char)dup_handling;
   return my_b_safe_write(file, (byte*) buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
 }
+#endif
 
 
 #ifdef MYSQL_CLIENT
diff --git a/sql/log_event.h b/sql/log_event.h
index 43a801da851d448ed069c0d624afd71efade26f4..72142db0aa7260494bba19522fb84e930d653c99 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -237,6 +237,7 @@ struct sql_ex_info
 #define Q_CATALOG_CODE          2
 #define Q_AUTO_INCREMENT	3
 #define Q_CHARSET_CODE          4
+#define Q_TIME_ZONE_CODE        5
 
 /* Intvar event post-header */
 
@@ -448,6 +449,7 @@ typedef struct st_last_event_info
   ulong auto_increment_increment, auto_increment_offset;
   bool charset_inited;
   char charset[6]; // 3 variables, each of them storable in 2 bytes
+  char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
   st_last_event_info()
     :flags2_inited(0), sql_mode_inited(0),
      auto_increment_increment(1),auto_increment_offset(1), charset_inited(0)
@@ -459,6 +461,7 @@ typedef struct st_last_event_info
       */
       bzero(db, sizeof(db));
       bzero(charset, sizeof(charset));
+      bzero(time_zone_str, sizeof(time_zone_str));
     }
 } LAST_EVENT_INFO;
 #endif
@@ -583,6 +586,7 @@ public:
     my_free((gptr) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
   }
 
+#ifndef MYSQL_CLIENT
   bool write_header(IO_CACHE* file, ulong data_length);
   virtual bool write(IO_CACHE* file)
   {
@@ -590,13 +594,14 @@ public:
             write_data_header(file) ||
             write_data_body(file));
   }
-  virtual bool is_artificial_event() { return 0; }
   virtual bool write_data_header(IO_CACHE* file)
   { return 0; }
   virtual bool write_data_body(IO_CACHE* file __attribute__((unused)))
   { return 0; }
+#endif
   virtual Log_event_type get_type_code() = 0;
   virtual bool is_valid() const = 0;
+  virtual bool is_artificial_event() { return 0; }
   inline bool get_cache_stmt() { return cache_stmt; }
   Log_event(const char* buf, const Format_description_log_event* description_event);
   virtual ~Log_event() { free_temp_buf();}
@@ -672,7 +677,7 @@ public:
     concerned) from here.
   */
 
-  int catalog_len;			// <= 255 char; -1 means uninited
+  uint catalog_len;			// <= 255 char; 0 means uninited
 
   /*
     We want to be able to store a variable number of N-bit status vars:
@@ -714,6 +719,8 @@ public:
   ulong sql_mode;
   ulong auto_increment_increment, auto_increment_offset;
   char charset[6];
+  uint time_zone_len; /* 0 means uninited */
+  const char *time_zone_str;
 
 #ifndef MYSQL_CLIENT
 
@@ -737,12 +744,13 @@ public:
   ~Query_log_event()
   {
     if (data_buf)
-    {
       my_free((gptr) data_buf, MYF(0));
-    }
   }
   Log_event_type get_type_code() { return QUERY_EVENT; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+  virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; }
+#endif
   bool is_valid() const { return query != 0; }
 
   /*
@@ -751,7 +759,6 @@ public:
   */
   virtual ulong get_post_header_size_for_derived() { return 0; }
   /* Writes derived event-specific part of post header. */
-  virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; }
 };
 
 #ifdef HAVE_REPLICATION
@@ -790,7 +797,9 @@ public:
   int get_data_size();
   bool is_valid() const { return master_host != 0; }
   Log_event_type get_type_code() { return SLAVE_EVENT; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
 };
 
 #endif /* HAVE_REPLICATION */
@@ -885,8 +894,10 @@ public:
   {
     return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT;
   }
+#ifndef MYSQL_CLIENT
   bool write_data_header(IO_CACHE* file);
   bool write_data_body(IO_CACHE* file);
+#endif
   bool is_valid() const { return table_name != 0; }
   int get_data_size()
   {
@@ -962,7 +973,9 @@ public:
                      const Format_description_log_event* description_event);
   ~Start_log_event_v3() {}
   Log_event_type get_type_code() { return START_EVENT_V3;}
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const { return 1; }
   int get_data_size()
   {
@@ -1004,7 +1017,9 @@ public:
                                const Format_description_log_event* description_event);
   ~Format_description_log_event() { my_free((gptr)post_header_len, MYF(0)); }
   Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;}
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const
   {
     return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN :
@@ -1054,7 +1069,9 @@ public:
   Log_event_type get_type_code() { return INTVAR_EVENT;}
   const char* get_var_type_name();
   int get_data_size() { return  9; /* sizeof(type) + sizeof(val) */;}
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const { return 1; }
 };
 
@@ -1092,7 +1109,9 @@ class Rand_log_event: public Log_event
   ~Rand_log_event() {}
   Log_event_type get_type_code() { return RAND_EVENT;}
   int get_data_size() { return 16; /* sizeof(ulonglong) * 2*/ }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const { return 1; }
 };
 
@@ -1127,7 +1146,9 @@ class Xid_log_event: public Log_event
   ~Xid_log_event() {}
   Log_event_type get_type_code() { return XID_EVENT;}
   int get_data_size() { return sizeof(xid); }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const { return 1; }
 };
 
@@ -1169,7 +1190,9 @@ public:
   User_var_log_event(const char* buf, const Format_description_log_event* description_event);
   ~User_var_log_event() {}
   Log_event_type get_type_code() { return USER_VAR_EVENT;}
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   bool is_valid() const { return 1; }
 };
 
@@ -1239,7 +1262,9 @@ public:
   Log_event_type get_type_code() { return ROTATE_EVENT;}
   int get_data_size() { return  ident_len + ROTATE_HEADER_LEN;}
   bool is_valid() const { return new_log_ident != 0; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
 };
 
 
@@ -1299,6 +1324,7 @@ public:
 	    4 + 1 + block_len);
   }
   bool is_valid() const { return inited_from_old || block != 0; }
+#ifndef MYSQL_CLIENT
   bool write_data_header(IO_CACHE* file);
   bool write_data_body(IO_CACHE* file);
   /*
@@ -1306,6 +1332,7 @@ public:
     write it as Load event - used on the slave
   */
   bool write_base(IO_CACHE* file);
+#endif
 };
 
 
@@ -1352,7 +1379,9 @@ public:
   Log_event_type get_type_code() { return APPEND_BLOCK_EVENT;}
   int get_data_size() { return  block_len + APPEND_BLOCK_HEADER_LEN ;}
   bool is_valid() const { return block != 0; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   const char* get_db() { return db; }
 };
 
@@ -1386,7 +1415,9 @@ public:
   Log_event_type get_type_code() { return DELETE_FILE_EVENT;}
   int get_data_size() { return DELETE_FILE_HEADER_LEN ;}
   bool is_valid() const { return file_id != 0; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   const char* get_db() { return db; }
 };
 
@@ -1419,7 +1450,9 @@ public:
   Log_event_type get_type_code() { return EXEC_LOAD_EVENT;}
   int get_data_size() { return  EXEC_LOAD_HEADER_LEN ;}
   bool is_valid() const { return file_id != 0; }
+#ifndef MYSQL_CLIENT
   bool write(IO_CACHE* file);
+#endif
   const char* get_db() { return db; }
 };
 
@@ -1507,7 +1540,9 @@ public:
   bool is_valid() const { return Query_log_event::is_valid() && file_id != 0; }
 
   ulong get_post_header_size_for_derived();
+#ifndef MYSQL_CLIENT
   bool write_post_header_for_derived(IO_CACHE* file);
+#endif
  };
 
 
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index ba9f382fc33e3ac3aac1f2fc1402127ca7320541..64e7b2cdccf62f80d88fcb6ca3b59ca347fc1191 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -257,6 +257,12 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
 /* Flag set if setup_tables already done */
 #define OPTION_SETUP_TABLES_DONE        (1L << 30)
 
+/* 
+  Maximum length of time zone name that we support 
+  (Time zone name is char(64) in db). mysqlbinlog needs it.
+*/
+#define MAX_TIME_ZONE_NAME_LENGTH 72
+
 /* The rest of the file is included in the server only */
 #ifndef MYSQL_CLIENT
 
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 23dbb22399b5bdc16a8866d174a04b94f8926d21..9e74c9452da33cfd0e28f2740ce5626830b7089d 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2095,27 +2095,6 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type)
  }
 }
 
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
-bool sys_var_character_set_server::check(THD *thd, set_var *var)
-{
-  /*
-    To be perfect we should fail even if we are a 5.0.3 slave, a 4.1 master,
-    and user wants to change our global character set variables. Because
-    replicating a 4.1 assumes those are not changed. But that's not easy to
-    do.
-  */
-  if ((var->type == OPT_GLOBAL) &&
-      (mysql_bin_log.is_open() ||
-       active_mi->slave_running || active_mi->rli.slave_running))
-  {
-    my_error(ER_LOGGING_PROHIBIT_CHANGING_OF, MYF(0),
-	     "character set, collation");
-    return 1;
-  }
-  return sys_var_character_set::check(thd,var);
-}
-#endif
-
 CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd,
 						       enum_var_type type)
 {
@@ -2208,20 +2187,6 @@ void sys_var_collation_database::set_default(THD *thd, enum_var_type type)
  }
 }
 
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
-bool sys_var_collation_server::check(THD *thd, set_var *var)
-{
-  if ((var->type == OPT_GLOBAL) &&
-      (mysql_bin_log.is_open() ||
-       active_mi->slave_running || active_mi->rli.slave_running))
-  {
-    my_error(ER_LOGGING_PROHIBIT_CHANGING_OF, MYF(0),
-	     "character set, collation");
-    return 1;
-  }
-  return sys_var_collation::check(thd,var);
-}
-#endif
 
 bool sys_var_collation_server::update(THD *thd, set_var *var)
 {
@@ -2560,16 +2525,6 @@ bool sys_var_thd_time_zone::check(THD *thd, set_var *var)
   String str(buff, sizeof(buff), &my_charset_latin1);
   String *res= var->value->val_str(&str);
 
-#if defined(HAVE_REPLICATION)
-  if ((var->type == OPT_GLOBAL) &&
-      (mysql_bin_log.is_open() ||
-       active_mi->slave_running || active_mi->rli.slave_running))
-  {
-    my_error(ER_LOGGING_PROHIBIT_CHANGING_OF, MYF(0), "time zone");
-    return 1;
-  }
-#endif
-
   if (!(var->save_result.time_zone=
         my_tz_find(res, thd->lex->time_zone_tables_used)))
   {
@@ -2605,7 +2560,18 @@ byte *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type,
   if (type == OPT_GLOBAL)
     return (byte *)(global_system_variables.time_zone->get_name()->ptr());
   else
+  {
+    /*
+      This is an ugly fix for replication: we don't replicate properly queries
+      invoking system variables' values to update tables; but
+      CONVERT_TZ(,,@@session.time_zone) is so popular that we make it
+      replicable (i.e. we tell the binlog code to store the session
+      timezone). If it's the global value which was used we can't replicate
+      (binlog code stores session value only).
+    */
+    thd->time_zone_used= 1;
     return (byte *)(thd->variables.time_zone->get_name()->ptr());
+  }
 }
 
 
diff --git a/sql/set_var.h b/sql/set_var.h
index d78c228c142f51a241293ab3905eb48bfa57ec80..585f6df3547d516183192c85a04fd5b7298373d4 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -565,9 +565,6 @@ class sys_var_character_set_server :public sys_var_character_set
 public:
   sys_var_character_set_server(const char *name_arg) :
     sys_var_character_set(name_arg) {}
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
-  bool check(THD *thd, set_var *var);
-#endif
   void set_default(THD *thd, enum_var_type type);
   CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type);
 };
@@ -603,9 +600,6 @@ class sys_var_collation_server :public sys_var_collation
 {
 public:
   sys_var_collation_server(const char *name_arg) :sys_var_collation(name_arg) {}
-#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
-  bool check(THD *thd, set_var *var);
-#endif
   bool update(THD *thd, set_var *var);
   void set_default(THD *thd, enum_var_type type);
   byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
diff --git a/sql/slave.cc b/sql/slave.cc
index 73dd0fd13c35479438e599d43c11c67908b7ec7b..9e42206d4a371eb9ff5b3590afa7ab061c7d887a 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1421,7 +1421,7 @@ not always make sense; please check the manual before using it).";
     We don't test equality of global collation_database either as it's is
     going to be deprecated (made read-only) in 4.1 very soon.
     The test is only relevant if master < 5.0.3 (we'll test only if it's older
-    than the 5 branch; < 5.0.3 was alpha...), as >= 5.0.3 master stores
+    than the 5 branch; < 5.0.4 were alpha...), as >= 5.0.4 master stores
     charset info in each binlog event.
     We don't do it for 3.23 because masters <3.23.50 hang on
     SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50). So finally we
@@ -1456,11 +1456,10 @@ be equal for replication to work";
     such check will broke everything for them. (And now everything will 
     work for them because by default both their master and slave will have 
     'SYSTEM' time zone).
-
-    TODO: when the new replication of timezones is sorted out with Dmitri,
-    change >= '4' to == '4'.
+    This check is only necessary for 4.x masters (and < 5.0.4 masters but
+    those were alpha).
   */
-  if ((*mysql->server_version >= '4') &&
+  if ((*mysql->server_version == '4') &&
       !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
       (master_res= mysql_store_result(mysql)))
   {
@@ -2770,6 +2769,18 @@ void set_slave_thread_options(THD* thd)
   thd->variables.completion_type= 0;
 }
 
+void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli)
+{
+  thd->variables.character_set_client=
+    global_system_variables.character_set_client;
+  thd->variables.collation_connection=
+    global_system_variables.collation_connection;
+  thd->variables.collation_server=
+    global_system_variables.collation_server;
+  thd->update_charset();
+  rli->cached_charset_invalidate();
+}
+
 /*
   init_slave_thread()
 */
diff --git a/sql/slave.h b/sql/slave.h
index ee5541ffe0800eaebb8aa6b6ca5d982431ad493c..bc41cd4decaca10baf5b6561b21066d3ae406ccb 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -562,6 +562,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,ulonglong pos,
 int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
 		     const char** errmsg);
 void set_slave_thread_options(THD* thd);
+void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli);
 void rotate_relay_log(MASTER_INFO* mi);
 
 extern "C" pthread_handler_decl(handle_slave_io,arg);
diff --git a/sql/tztime.cc b/sql/tztime.cc
index bd9d49f0ab019d4b10b5f72c4ee3d23d2cd6dc4d..983c630071e611e2f5934e75ab07d96c17c87ef6 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -2178,7 +2178,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
   DBUG_PRINT("enter", ("time zone name='%s'",
                       name ? ((String *)name)->c_ptr() : "NULL"));
 
-  DBUG_ASSERT(!time_zone_tables_exist || tz_tables);
+  DBUG_ASSERT(!time_zone_tables_exist || tz_tables || current_thd->slave_thread);
 
   if (!name)
     DBUG_RETURN(0);
@@ -2210,7 +2210,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
                                                    (const byte *)name->ptr(),
                                                    name->length())))
       result_tz= tmp_tzname->tz;
-    else if (time_zone_tables_exist)
+    else if (time_zone_tables_exist && tz_tables)
       result_tz= tz_load_from_open_tables(name, tz_tables);
   }
 
@@ -2219,6 +2219,58 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
   DBUG_RETURN(result_tz);
 }
 
+
+/*
+  A more standalone version of my_tz_find(): will open tz tables if needed.
+  This is so far only used by replication, where time zone setting does not
+  happen in the usual query context.
+
+  SYNOPSIS
+    my_tz_find_with_opening_tz_tables()
+      thd  - pointer to thread's THD structure
+      name - time zone specification
+
+  DESCRIPTION
+    This function tries to find a time zone which matches the named passed in
+    argument. If it fails, it will open time zone tables and re-try the
+    search.
+    This function is needed for the slave SQL thread, which does not do the
+    addition of time zone tables which is usually done during query parsing
+    (as time zone setting by slave does not happen in mysql_parse() but
+    before). So it needs to open tz tables by itself if needed.
+    See notes of my_tz_find() as they also apply here.
+
+  RETURN VALUE
+    Pointer to corresponding Time_zone object. 0 - in case of bad time zone
+    specification or other error.
+
+*/
+Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name)
+{
+  Time_zone *tz;
+  DBUG_ENTER("my_tz_find_with_opening_tables");
+  DBUG_ASSERT(thd);
+  DBUG_ASSERT(thd->slave_thread); // intended for use with slave thread only
+  if (!(tz= my_tz_find(name, 0)) && time_zone_tables_exist)
+  {
+    /*
+      Probably we have not loaded this time zone yet so let us look it up in
+      our time zone tables. Note that if we don't have tz tables on this
+      slave, we don't even try.
+    */
+    TABLE_LIST tables[4];
+    TABLE_LIST *dummy;
+    TABLE_LIST **dummyp= &dummy;
+    tz_init_table_list(tables, &dummyp);
+    if (simple_open_n_lock_tables(thd, tables))
+      DBUG_RETURN(0);
+    tz= my_tz_find(name, tables);
+    /* We need to close tables _now_ to not pollute coming query */
+    close_thread_tables(thd);
+  }
+  DBUG_RETURN(tz);
+}
+
 #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
 
 
diff --git a/sql/tztime.h b/sql/tztime.h
index caf663fc8cb1a8e56c986d8b9f6ee45a8863b24a..777e521d76141e0207c9de3d767da8ff0db01bd0 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -61,6 +61,7 @@ extern Time_zone * my_tz_UTC;
 extern Time_zone * my_tz_SYSTEM;
 extern TABLE_LIST * my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr);
 extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables);
+extern Time_zone * my_tz_find_with_opening_tz_tables(THD *thd, const String *name);
 extern my_bool     my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
 extern void        my_tz_free();
 
@@ -96,10 +97,4 @@ inline bool my_tz_check_n_skip_implicit_tables(TABLE_LIST **table,
   return FALSE;
 }
 
-/* 
-  Maximum length of time zone name that we support 
-  (Time zone name is char(64) in db)
-*/
-#define MAX_TIME_ZONE_NAME_LENGTH 72
-
 #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */