diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index 778625e9e75cf26082bfaa6ca1e731eef5b68dc8..cf5405565b86a5dafa82da74101f0a0604e6a329 100644
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -52,7 +52,8 @@ debug_cflags="-DEXTRA_DEBUG -DFORCE_INIT_OF_VARS -DSAFEMALLOC -DSAFE_MUTEX -O2"
 
 base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti"
 
-base_configs="--prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static"
+base_configs="--prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-all-static \
+ --with-client-ldflags=-all-static"
 alpha_configs=""	# Not used yet
 pentium_configs=""
 sparc_configs=""
diff --git a/client/mysqltest.c b/client/mysqltest.c
index f1fcae6bf6d2d91d3785ee1dd2a3252bf7c158ac..cffac3982550780eb1d527e73962dae86dc96f1c 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -43,7 +43,7 @@
 
 **********************************************************************/
 
-#define MTEST_VERSION "1.8"
+#define MTEST_VERSION "1.9"
 
 #include <global.h>
 #include <my_sys.h>
@@ -159,6 +159,8 @@ Q_SYNC_WITH_MASTER, Q_ERROR,
 Q_SEND,             Q_REAP, 
 Q_DIRTY_CLOSE,      Q_REPLACE,
 Q_PING,             Q_EVAL,
+Q_RPL_PROBE,        Q_ENABLE_RPL_PARSE,
+Q_DISABLE_RPL_PARSE,
 Q_UNKNOWN,                             /* Unknown command.   */
 Q_COMMENT,                             /* Comments, ignored. */
 Q_COMMENT_WITH_COMMAND
@@ -188,6 +190,8 @@ const char *command_names[] = {
   "send",             "reap", 
   "dirty_close",      "replace_result",
   "ping",             "eval",
+  "rpl_probe",        "enable_rpl_parse",
+  "disable_rpl_parse",
   0
 };
 
@@ -642,6 +646,11 @@ int do_sync_with_master(struct st_query* q)
   char query_buf[FN_REFLEN+128];
   int offset = 0;
   char* p = q->first_argument;
+  int rpl_parse;
+
+  rpl_parse = mysql_rpl_parse_enabled(mysql);
+  mysql_disable_rpl_parse(mysql);
+  
   if(*p)
     offset = atoi(p);
   
@@ -658,7 +667,10 @@ int do_sync_with_master(struct st_query* q)
   if(!row[0])
     die("Error on slave while syncing with master");
   mysql_free_result(res);
-      
+
+  if(rpl_parse)
+    mysql_enable_rpl_parse(mysql);
+  
   return 0;
 }
 
@@ -667,6 +679,11 @@ int do_save_master_pos()
   MYSQL_RES* res;
   MYSQL_ROW row;
   MYSQL* mysql = &cur_con->mysql;
+  int rpl_parse;
+
+  rpl_parse = mysql_rpl_parse_enabled(mysql);
+  mysql_disable_rpl_parse(mysql);
+  
   if(mysql_query(mysql, "show master status"))
     die("At line %u: failed in show master status: %d: %s", start_lineno,
 	mysql_errno(mysql), mysql_error(mysql));
@@ -678,6 +695,9 @@ int do_save_master_pos()
   strncpy(master_pos.file, row[0], sizeof(master_pos.file));
   master_pos.pos = strtoul(row[1], (char**) 0, 10); 
   mysql_free_result(res);
+  
+  if(rpl_parse)
+    mysql_enable_rpl_parse(mysql);
       
   return 0;
 }
@@ -702,6 +722,26 @@ int do_let(struct st_query* q)
   return var_set(var_name, var_name_end, var_val_start, p);
 }
 
+int do_rpl_probe(struct st_query* __attribute__((unused)) q)
+{
+  if(mysql_rpl_probe(&cur_con->mysql))
+    die("Failed in mysql_rpl_probe(): %s", mysql_error(&cur_con->mysql));
+  return 0;
+}
+
+int do_enable_rpl_parse(struct st_query* __attribute__((unused)) q)
+{
+  mysql_enable_rpl_parse(&cur_con->mysql);
+  return 0;
+}
+
+int do_disable_rpl_parse(struct st_query* __attribute__((unused)) q)
+{
+  mysql_disable_rpl_parse(&cur_con->mysql);
+  return 0;
+}
+
+
 int do_sleep(struct st_query* q)
 {
   char* p=q->first_argument;
@@ -1825,6 +1865,9 @@ int main(int argc, char** argv)
       case Q_DISCONNECT:
       case Q_DIRTY_CLOSE:	
 	close_connection(q); break;
+      case Q_RPL_PROBE: do_rpl_probe(q); break;
+      case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break;
+      case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break;
       case Q_SOURCE: do_source(q); break;
       case Q_SLEEP: do_sleep(q); break;
       case Q_INC: do_inc(q); break;
@@ -1892,7 +1935,7 @@ int main(int argc, char** argv)
       case Q_SAVE_MASTER_POS: do_save_master_pos(); break;	
       case Q_SYNC_WITH_MASTER: do_sync_with_master(q); break;	
       case Q_COMMENT:				/* Ignore row */
-      case Q_COMMENT_WITH_COMMAND:
+      case Q_COMMENT_WITH_COMMAND: 
       case Q_PING:
 	(void) mysql_ping(&cur_con->mysql);
 	break;
diff --git a/include/errmsg.h b/include/errmsg.h
index 12a3ee5557a35e0faa49da569d4d2bd15550a733..427174ffa53b76827ffc9961edc7d1cf23bb58e2 100644
--- a/include/errmsg.h
+++ b/include/errmsg.h
@@ -54,3 +54,10 @@ extern const char *client_errors[];	/* Error messages */
 #define CR_CANT_READ_CHARSET	2019
 #define CR_NET_PACKET_TOO_LARGE 2020
 #define CR_EMBEDDED_CONNECTION	2021
+#define CR_PROBE_SLAVE_STATUS   2022
+#define CR_PROBE_SLAVE_HOSTS    2023
+#define CR_PROBE_SLAVE_CONNECT  2024
+#define CR_PROBE_MASTER_CONNECT 2025
+
+
+
diff --git a/include/mysql.h b/include/mysql.h
index 5d06f96d223724c35ef6cd07c374ac149bfda3c1..4ce7e80bcb9329622ee5aadd42170d2470657c61 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -154,6 +154,14 @@ enum mysql_option { MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS,
 enum mysql_status { MYSQL_STATUS_READY,MYSQL_STATUS_GET_RESULT,
 		    MYSQL_STATUS_USE_RESULT};
 
+/* there are three types of queries - the ones that have to go to
+     the master, the ones that go to a slave, and the adminstrative
+     type which must happen on the pivot connectioin
+*/
+enum mysql_rpl_type { MYSQL_RPL_MASTER, MYSQL_RPL_SLAVE,
+			      MYSQL_RPL_ADMIN };
+  
+
 typedef struct st_mysql {
   NET		net;			/* Communication parameters */
   gptr		connector_fd;		/* ConnectorFd for SSL */
@@ -183,7 +191,15 @@ typedef struct st_mysql {
   struct st_mysql* master, *next_slave;
   
   struct st_mysql* last_used_slave; /* needed for round-robin slave pick */
-  my_bool is_slave; /* will be false for a lone connection */
+  struct st_mysql* last_used_con; /* needed for send/read/store/use
+				      result to work
+				      correctly with replication
+				   */
+  my_bool rpl_pivot; /* set if this is the original connection,
+			not a master or a slave we have added though
+			mysql_rpl_probe() or mysql_set_master()/
+			mysql_add_slave()
+		     */
 } MYSQL;
 
 
@@ -261,9 +277,13 @@ int		STDCALL mysql_real_query(MYSQL *mysql, const char *q,
 /* perform query on master */
 int		STDCALL mysql_master_query(MYSQL *mysql, const char *q,
 					unsigned int length);
+int		STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
+					unsigned int length);
 /* perform query on slave */  
 int		STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
 					unsigned int length);
+int		STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
+					unsigned int length);
 
 /* enable/disable parsing of all queries to decide
    if they go on master or slave */
@@ -278,11 +298,22 @@ void            STDCALL mysql_disable_reads_from_master(MYSQL* mysql);
 /* get the value of the master read flag */  
 int             STDCALL mysql_reads_from_master_enabled(MYSQL* mysql);
 
-int             STDCALL mysql_query_goes_to_master(const char* q, int len);  
+enum mysql_rpl_type     STDCALL mysql_rpl_query_type(const char* q, int len);  
 
 /* discover the master and its slaves */  
-int             STDCALL mysql_rpl_probe(MYSQL* mysql);  
-
+int             STDCALL mysql_rpl_probe(MYSQL* mysql);
+  
+/* set the master, close/free the old one, if it is not a pivot */
+int             STDCALL mysql_set_master(MYSQL* mysql, const char* host,
+					   unsigned int port,
+					   const char* user,
+					   const char* passwd);
+int             STDCALL mysql_add_slave(MYSQL* mysql, const char* host,
+					   unsigned int port,
+					   const char* user,
+					   const char* passwd);
+  
+  
 int		STDCALL mysql_create_db(MYSQL *mysql, const char *DB);
 int		STDCALL mysql_drop_db(MYSQL *mysql, const char *DB);
 int		STDCALL mysql_shutdown(MYSQL *mysql);
diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c
index 71fc25fd77c58be404b8ff71b33d116a6baeebf3..f0a1692453a7c0dc949c5c82868ed889a4eb72db 100644
--- a/libmysql/errmsg.c
+++ b/libmysql/errmsg.c
@@ -16,7 +16,7 @@
    MA 02111-1307, USA */
 
 /* Error messages for MySQL clients */
-/* error messages for the demon is in share/language/errmsg.sys */
+/* error messages for the daemon is in share/language/errmsg.sys */
 
 #include <global.h>
 #include <my_sys.h>
@@ -47,6 +47,10 @@ const char *client_errors[]=
   "Can't initialize character set %-.64s (path: %-.64s)",
   "Got packet bigger than 'max_allowed_packet'",
   "Embedded server",
+  "Error on SHOW SLAVE STATUS: %-.64s",
+  "Error on SHOW SLAVE HOSTS: %-.64s",
+  "Error connecting to slave: %-.64s",
+  "Error connecting to master: %-.64s"
 };
 
 /* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */
@@ -76,6 +80,10 @@ const char *client_errors[]=
   "Não pode inicializar conjunto de caracteres %-.64s (caminho %-.64s)",
   "Obteve pacote maior do que 'max_allowed_packet'",
   "Embedded server"
+  "Error on SHOW SLAVE STATUS: %-.64s",
+  "Error on SHOW SLAVE HOSTS: %-.64s",
+  "Error connecting to slave: %-.64s",
+  "Error connecting to master: %-.64s"
 };
 
 #else /* ENGLISH */
@@ -102,7 +110,11 @@ const char *client_errors[]=
   "Can't set state of named pipe to host: %-.64s  pipe: %-.32s (%lu)",
   "Can't initialize character set %-.64s (path: %-.64s)",
   "Got packet bigger than 'max_allowed_packet'",
-  "Embedded server"
+  "Embedded server",
+  "Error on SHOW SLAVE STATUS:",
+  "Error on SHOW SLAVE HOSTS:",
+  "Error connecting to slave:",
+  "Error connecting to master:"
 };
 #endif
 
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index c45dce981a8984117ede0ab664c19b4f08b37a58..d6f5b7c523f957cf0f98a6a30ec34dc6c746523d 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -109,6 +109,12 @@ static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
 #define reset_sigpipe(mysql)
 #endif
 
+static MYSQL* spawn_init(MYSQL* parent, const char* host,
+			 unsigned int port,
+			 const char* user,
+			 const char* passwd);
+
+
 /****************************************************************************
 * A modified version of connect().  connect2() allows you to specify
 * a timeout value, in seconds, that we should wait until we
@@ -1001,14 +1007,35 @@ read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
 int STDCALL mysql_master_query(MYSQL *mysql, const char *q,
 					unsigned int length)
 {
-  if(!length)
+  if(mysql_master_send_query(mysql, q, length))
+    return 1;
+  return mysql_read_query_result(mysql);
+}
+
+int STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
+					unsigned int length)
+{
+  MYSQL*master = mysql->master;
+  if (!length)
     length = strlen(q);
-  return mysql_real_query(mysql->master, q, length);
+  if (!master->net.vio && !mysql_real_connect(master,0,0,0,0,0,0,0))
+    return 1;
+  mysql->last_used_con = master;
+  return simple_command(master, COM_QUERY, q, length, 1);
 }
 
+
 /* perform query on slave */  
 int STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
 					unsigned int length)
+{
+  if(mysql_slave_send_query(mysql, q, length))
+    return 1;
+  return mysql_read_query_result(mysql);
+}
+
+int STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q,
+					unsigned int length)
 {
   MYSQL* last_used_slave, *slave_to_use = 0;
   
@@ -1019,12 +1046,16 @@ int STDCALL mysql_slave_query(MYSQL *mysql, const char *q,
   /* next_slave is always safe to use - we have a circular list of slaves
      if there are no slaves, mysql->next_slave == mysql
   */
-  mysql->last_used_slave = slave_to_use;
+  mysql->last_used_con = mysql->last_used_slave = slave_to_use;
   if(!length)
     length = strlen(q);
-  return mysql_real_query(slave_to_use, q, length);
+  if(!slave_to_use->net.vio && !mysql_real_connect(slave_to_use, 0,0,0,
+						   0,0,0,0))
+    return 1;
+  return simple_command(slave_to_use, COM_QUERY, q, length, 1);
 }
 
+
 /* enable/disable parsing of all queries to decide
    if they go on master or slave */
 void STDCALL mysql_enable_rpl_parse(MYSQL* mysql)
@@ -1060,40 +1091,100 @@ int STDCALL mysql_reads_from_master_enabled(MYSQL* mysql)
   return !(mysql->options.no_master_reads);
 }
 
+/* We may get an error while doing replication internals.
+   In this case, we add a special explanation to the original
+   error
+*/
+static inline void expand_error(MYSQL* mysql, int error)
+{
+  char tmp[MYSQL_ERRMSG_SIZE];
+  char* p, *tmp_end;
+  tmp_end = strnmov(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE);
+  p = strnmov(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE);
+  memcpy(p, tmp, tmp_end - tmp);
+  mysql->net.last_errno = error;
+}
+
 /* This function assumes we have just called SHOW SLAVE STATUS and have
    read the given result and row
 */
 static inline int get_master(MYSQL* mysql, MYSQL_RES* res, MYSQL_ROW row)
 {
   MYSQL* master;
-  if(mysql_num_rows(res) < 3)
+  if(mysql_num_fields(res) < 3)
     return 1; /* safety */
-  if(!(master = mysql_init(0)))
-    return 1;
-
+  
   /* use the same username and password as the original connection */
-  master->user = mysql->user;
-  master->passwd = mysql->passwd;
-  master->host = row[0];
-  master->port = atoi(row[2]);
-  master->db = mysql->db;
+  if(!(master = spawn_init(mysql, row[0], atoi(row[2]), 0, 0)))
+    return 1;
   mysql->master = master;
   return 0;
 }
 
+/* assuming we already know that mysql points to a master connection,
+   retrieve all the slaves
+*/
 static inline int get_slaves_from_master(MYSQL* mysql)
 {
-  if(!mysql->net.vio && !mysql_real_connect(mysql, mysql->host, mysql->user,
-				      mysql->passwd, mysql->db, mysql->port,
-				      mysql->unix_socket, mysql->client_flag))
+  MYSQL_RES* res = 0;
+  MYSQL_ROW row;
+  int error = 1;
+  int has_auth_info;
+  if (!mysql->net.vio && !mysql_real_connect(mysql,0,0,0,0,0,0,0))
+  {
+    expand_error(mysql, CR_PROBE_MASTER_CONNECT);
     return 1;
-  /* more to be written */
-  return 0;
+  }
+
+  if (mysql_query(mysql, "SHOW SLAVE HOSTS") ||
+     !(res = mysql_store_result(mysql)))
+  {
+    expand_error(mysql, CR_PROBE_SLAVE_HOSTS);
+    return 1;
+  }
+
+  switch (mysql_num_fields(res))
+  {
+  case 3: has_auth_info = 0; break;
+  case 5: has_auth_info = 1; break;
+  default:
+    goto err;
+  }
+
+  while ((row = mysql_fetch_row(res)))
+  {
+    MYSQL* slave;
+    const char* tmp_user, *tmp_pass;
+
+    if (has_auth_info)
+    {
+      tmp_user = row[3];
+      tmp_pass = row[4];
+    }
+    else
+    {
+      tmp_user = mysql->user;
+      tmp_pass = mysql->passwd;
+    }
+
+    if(!(slave = spawn_init(mysql, row[1], atoi(row[2]),
+			    tmp_user, tmp_pass)))
+      goto err;
+      
+    /* Now add slave into the circular linked list */
+    slave->next_slave = mysql->next_slave;
+    mysql->next_slave = slave;
+  }
+  error = 0;
+err:
+  if(res)
+   mysql_free_result(res);
+  return error;
 }
 
 int STDCALL mysql_rpl_probe(MYSQL* mysql)
 {
-  MYSQL_RES* res;
+  MYSQL_RES* res = 0;
   MYSQL_ROW row;
   int error = 1;
   /* first determine the replication role of the server we connected to
@@ -1103,30 +1194,34 @@ int STDCALL mysql_rpl_probe(MYSQL* mysql)
      a non-empty master host. However, it is more reliable to check 
      for empty master than whether the slave thread is actually running
   */
-  if(mysql_query(mysql, "SHOW SLAVE STATUS") ||
+  if (mysql_query(mysql, "SHOW SLAVE STATUS") ||
      !(res = mysql_store_result(mysql)))
+  {
+    expand_error(mysql, CR_PROBE_SLAVE_STATUS);
     return 1;
-
-  if(!(row = mysql_fetch_row(res)))
+  }
+  
+  if (!(row = mysql_fetch_row(res)))
     goto err;
 
   /* check master host for emptiness/NULL */
-  if(row[0] && *(row[0]))
+  if (row[0] && *(row[0]))
   {
     /* this is a slave, ask it for the master */
-    if(get_master(mysql, res, row) || get_slaves_from_master(mysql))
+    if (get_master(mysql, res, row) || get_slaves_from_master(mysql))
       goto err;
   }
   else
   {
     mysql->master = mysql;
-    if(get_slaves_from_master(mysql))
+    if (get_slaves_from_master(mysql))
       goto err;
   }
 
   error = 0;
 err:
-  mysql_free_result(res);
+  if(res)
+    mysql_free_result(res);
   return error;
 }
 
@@ -1141,7 +1236,8 @@ err:
    mysql_master_query() or mysql_slave_query() explicitly in the place
    where we have made the wrong decision
 */
-int STDCALL mysql_query_goes_to_master(const char* q, int len)
+enum mysql_rpl_type
+STDCALL mysql_rpl_query_type(const char* q, int len)
 {
   const char* q_end;
   q_end = (len) ? q + len : strend(q);
@@ -1156,9 +1252,17 @@ int STDCALL mysql_query_goes_to_master(const char* q, int len)
        case 'l':  /* lock tables or load data infile */
        case 'd':  /* drop or delete */
        case 'a':  /* alter */
-	 return 1;
+	 return MYSQL_RPL_MASTER;
+       case 'c':  /* create or check */
+	 return tolower(q[1]) == 'h' ? MYSQL_RPL_ADMIN : MYSQL_RPL_MASTER ;
+       case 's': /* select or show */
+	 return tolower(q[1] == 'h') ? MYSQL_RPL_ADMIN : MYSQL_RPL_SLAVE;
+       case 'f': /* flush */
+       case 'r': /* repair */
+       case 'g': /* grant */
+	 return MYSQL_RPL_ADMIN;
        default:
-	 return 0;
+	 return MYSQL_RPL_SLAVE;
        }
   }
 
@@ -1184,8 +1288,12 @@ mysql_init(MYSQL *mysql)
   else
     bzero((char*) (mysql),sizeof(*(mysql)));
   mysql->options.connect_timeout=CONNECT_TIMEOUT;
-  mysql->next_slave = mysql->master = mysql;
+  mysql->last_used_con = mysql->next_slave = mysql->master = mysql;
   mysql->last_used_slave = 0;
+  /* By default, we are a replication pivot. The caller must reset it
+     after we return if this is not the case.
+  */
+  mysql->rpl_pivot = 1; 
 #if defined(SIGPIPE) && defined(THREAD)
   if (!((mysql)->client_flag & CLIENT_IGNORE_SIGPIPE))
     (void) signal(SIGPIPE,pipe_sig_handler);
@@ -1723,6 +1831,9 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
     mysql->reconnect=reconnect;
   }
 
+  if (mysql->options.rpl_probe && mysql_rpl_probe(mysql))
+    goto error;
+  
   DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
   reset_sigpipe(mysql);
   DBUG_RETURN(mysql);
@@ -1864,6 +1975,21 @@ mysql_close(MYSQL *mysql)
 /*    ((VioConnectorFd*)(mysql->connector_fd))->delete();
     mysql->connector_fd = 0;*/
 #endif /* HAVE_OPENSSL */
+    
+    /* free/close slave list */
+    if (mysql->rpl_pivot)
+    {
+      MYSQL* tmp;
+      for (tmp = mysql->next_slave; tmp != mysql; )
+      {
+	/* trick to avoid following freed pointer */
+	MYSQL* tmp1 = tmp->next_slave;
+	mysql_close(tmp);
+	tmp = tmp1;
+      }
+    }
+    if(mysql != mysql->master)
+      mysql_close(mysql->master);
     if (mysql->free_me)
       my_free((gptr) mysql,MYF(0));
   }
@@ -1882,6 +2008,67 @@ mysql_query(MYSQL *mysql, const char *query)
   return mysql_real_query(mysql,query, (uint) strlen(query));
 }
 
+static MYSQL* spawn_init(MYSQL* parent, const char* host,
+					   unsigned int port,
+					   const char* user,
+					   const char* passwd)
+{
+  MYSQL* child;
+  if (!(child = mysql_init(0)))
+    return 0;
+  
+  child->options.user = my_strdup((user) ? user :
+				  (parent->user ? parent->user :
+				       parent->options.user), MYF(0));
+  child->options.password = my_strdup((passwd) ? passwd : (parent->passwd ?
+						    parent->passwd :
+				       parent->options.password), MYF(0));
+  child->options.port = port;
+  child->options.host = my_strdup((host) ? host : (parent->host ?
+						    parent->host :
+				       parent->options.host), MYF(0));
+  if(parent->db)
+    child->options.db = my_strdup(parent->db, MYF(0));
+  else if(parent->options.db)
+    child->options.db = my_strdup(parent->options.db, MYF(0));
+
+  child->options.rpl_parse = child->options.rpl_probe = child->rpl_pivot = 0;
+    
+  return child;
+}
+
+
+int
+STDCALL mysql_set_master(MYSQL* mysql, const char* host,
+					   unsigned int port,
+					   const char* user,
+					   const char* passwd)
+{
+  if (mysql->master != mysql && !mysql->master->rpl_pivot)
+    mysql_close(mysql->master);
+  if(!(mysql->master = spawn_init(mysql, host, port, user, passwd)))
+    return 1;
+  mysql->master->rpl_pivot = 0;
+  mysql->master->options.rpl_parse = 0;
+  mysql->master->options.rpl_probe = 0;
+  return 0;
+}
+
+int
+STDCALL mysql_add_slave(MYSQL* mysql, const char* host,
+					   unsigned int port,
+					   const char* user,
+					   const char* passwd)
+{
+  MYSQL* slave;
+  if(!(slave = spawn_init(mysql, host, port, user, passwd)))
+    return 1;
+  slave->next_slave = mysql->next_slave;
+  mysql->next_slave = slave;
+  return 0;
+}
+
+
 /*
   Send the query and return so we can do something else.
   Needs to be followed by mysql_read_query_result() when we want to
@@ -1891,6 +2078,20 @@ mysql_query(MYSQL *mysql, const char *query)
 int STDCALL
 mysql_send_query(MYSQL* mysql, const char* query, uint length)
 {
+  if (mysql->options.rpl_parse && mysql->rpl_pivot)
+  {
+    switch (mysql_rpl_query_type(query, length))
+    {
+    case MYSQL_RPL_MASTER:
+      return mysql_master_send_query(mysql, query, length);
+    case MYSQL_RPL_SLAVE:
+      return mysql_slave_send_query(mysql, query, length);
+    case MYSQL_RPL_ADMIN: /*fall through */
+    }
+  }
+
+  mysql->last_used_con = mysql;
+
   return simple_command(mysql, COM_QUERY, query, length, 1);
 }
 
@@ -1902,6 +2103,11 @@ int STDCALL mysql_read_query_result(MYSQL *mysql)
   uint length;
   DBUG_ENTER("mysql_read_query_result");
 
+  /* read from the connection which we actually used, which
+     could differ from the original connection if we have slaves
+   */
+  mysql = mysql->last_used_con;
+  
   if ((length = net_safe_read(mysql)) == packet_error)
     DBUG_RETURN(-1);
   free_old_query(mysql);			/* Free old result */
@@ -1948,7 +2154,8 @@ mysql_real_query(MYSQL *mysql, const char *query, uint length)
   DBUG_ENTER("mysql_real_query");
   DBUG_PRINT("enter",("handle: %lx",mysql));
   DBUG_PRINT("query",("Query = \"%s\"",query));
-  if (simple_command(mysql,COM_QUERY,query,length,1))
+  
+  if (mysql_send_query(mysql,query,length))
     DBUG_RETURN(-1);
   DBUG_RETURN(mysql_read_query_result(mysql));
 }
@@ -2020,6 +2227,9 @@ mysql_store_result(MYSQL *mysql)
   MYSQL_RES *result;
   DBUG_ENTER("mysql_store_result");
 
+  /* read from the actually used connection */
+  mysql = mysql->last_used_con;
+  
   if (!mysql->fields)
     DBUG_RETURN(0);
   if (mysql->status != MYSQL_STATUS_GET_RESULT)
@@ -2072,6 +2282,8 @@ mysql_use_result(MYSQL *mysql)
   MYSQL_RES *result;
   DBUG_ENTER("mysql_use_result");
 
+  mysql = mysql->last_used_con;
+  
   if (!mysql->fields)
     DBUG_RETURN(0);
   if (mysql->status != MYSQL_STATUS_GET_RESULT)
@@ -2525,32 +2737,32 @@ uint STDCALL mysql_field_tell(MYSQL_RES *res)
 
 unsigned int STDCALL mysql_field_count(MYSQL *mysql)
 {
-  return mysql->field_count;
+  return mysql->last_used_con->field_count;
 }
 
 my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql)
 {
-  return (mysql)->affected_rows;
+  return mysql->last_used_con->affected_rows;
 }
 
 my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
 {
-  return (mysql)->insert_id;
+  return mysql->last_used_con->insert_id;
 }
 
 uint STDCALL mysql_errno(MYSQL *mysql)
 {
-  return (mysql)->net.last_errno;
+  return mysql->net.last_errno;
 }
 
 char * STDCALL mysql_error(MYSQL *mysql)
 {
-  return (mysql)->net.last_error;
+  return mysql->net.last_error;
 }
 
 char *STDCALL mysql_info(MYSQL *mysql)
 {
-  return (mysql)->info;
+  return mysql->info;
 }
 
 ulong STDCALL mysql_thread_id(MYSQL *mysql)
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 969255d5e6e8033630828feace31e57236cd372d..93bb00687a5dd67e9f2b5b136a12d72218843105 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -124,6 +124,7 @@ USE_RUNNING_SERVER=1
 DO_GCOV=""
 DO_GDB=""
 DO_DDD=""
+DO_CLIENT_GDB=""
 SLEEP_TIME=2
 DBUSER=""
 
@@ -165,13 +166,19 @@ while test $# -gt 0; do
       ;;  
     --gdb )
       if [ x$BINARY_DIST = x1 ] ; then
-	$ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with -gdb option"
+	$ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with --gdb option"
       fi
       DO_GDB=1
       ;;
+    --client-gdb )
+      if [ x$BINARY_DIST = x1 ] ; then
+	$ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with --client-gdb option"
+      fi
+      DO_CLIENT_GDB=1
+      ;;
     --ddd )
       if [ x$BINARY_DIST = x1 ] ; then
-	$ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with -gdb option"
+	$ECHO "Note: you will get more meaningful output on a source distribution compiled with debugging option when running tests with --ddd option"
       fi
       DO_DDD=1
       ;;
@@ -273,7 +280,10 @@ then
 fi
 
 
-MYSQL_TEST="$MYSQL_TEST --no-defaults --socket=$MASTER_MYSOCK --database=$DB --user=$DBUSER --password=$DBPASSWD --silent -v --tmpdir=$MYSQL_TMP_DIR"
+MYSQL_TEST_ARGS="--no-defaults --socket=$MASTER_MYSOCK --database=$DB --user=$DBUSER --password=$DBPASSWD --silent -v --tmpdir=$MYSQL_TMP_DIR"
+MYSQL_TEST_BIN=$MYSQL_TEST
+MYSQL_TEST="$MYSQL_TEST $MYSQL_TEST_ARGS"
+GDB_CLIENT_INIT=$MYSQL_TMP_DIR/gdbinit.client
 GDB_MASTER_INIT=$MYSQL_TMP_DIR/gdbinit.master
 GDB_SLAVE_INIT=$MYSQL_TMP_DIR/gdbinit.slave
 GCOV_MSG=$MYSQL_TMP_DIR/mysqld-gcov.out
@@ -316,6 +326,15 @@ show_failed_diff ()
   fi  
 }
 
+do_gdb_test ()
+{
+  mysql_test_args="$MYSQL_TEST_ARGS $1"
+  $ECHO "set args $mysql_test_args < $2" > $GDB_CLIENT_INIT
+  echo "Set breakpoints ( if needed) and type 'run' in gdb window"
+  #this xterm should not be backgrounded
+  xterm -title "Client" -e gdb -x $GDB_CLIENT_INIT $MYSQL_TEST_BIN
+}
+
 error () {
     $ECHO  "Error:  $1"
     exit 1
@@ -694,8 +713,13 @@ run_testcase ()
   
  if [ -f $tf ] ; then
     $RM -f r/$tname.*reject
-    mytime=`$TIME -p $MYSQL_TEST -R r/$tname.result $EXTRA_MYSQL_TEST_OPT \
-     < $tf 2> $TIMEFILE`
+    mysql_test_args="-R r/$tname.result $EXTRA_MYSQL_TEST_OPT"
+    if [ -z "$DO_CLIENT_GDB" ] ; then
+     mytime=`$TIME -p $MYSQL_TEST  $mysql_test_args < $tf 2> $TIMEFILE`
+    else
+     do_gdb_test "$mysql_test_args" "$tf"
+    fi
+     
     res=$?
 
     if [ $res = 0 ]; then
diff --git a/mysql-test/r/rpl_magic.result b/mysql-test/r/rpl_magic.result
new file mode 100644
index 0000000000000000000000000000000000000000..449a6bca68c00a92d2aa4043a384f55cd335365f
--- /dev/null
+++ b/mysql-test/r/rpl_magic.result
@@ -0,0 +1,22 @@
+n
+1
+2
+3
+4
+5
+n
+1
+2
+3
+4
+n
+1
+2
+3
+4
+n
+1
+2
+3
+4
+5
diff --git a/mysql-test/t/rpl_magic.test b/mysql-test/t/rpl_magic.test
new file mode 100644
index 0000000000000000000000000000000000000000..18f1cea34a3aa8c9578217845e23beda72752f25
--- /dev/null
+++ b/mysql-test/t/rpl_magic.test
@@ -0,0 +1,30 @@
+source include/master-slave.inc;
+
+#first, make sure the slave has had enough time to register
+connection master;
+save_master_pos;
+connection slave;
+sync_with_master;
+
+#discover slaves
+connection master;
+rpl_probe;
+
+#turn on master/slave query direction auto-magic
+enable_rpl_parse;
+drop table if exists t1;
+create table t1 ( n int);
+insert into t1 values (1),(2),(3),(4);
+disable_rpl_parse;
+save_master_pos;
+enable_rpl_parse;
+connection slave;
+sync_with_master;
+insert into t1 values(5);
+connection master;
+select * from t1;
+select * from t1;
+disable_rpl_parse;
+select * from t1;
+connection slave;
+select * from t1;