diff --git a/mysql-test/r/rpl000009.result b/mysql-test/r/rpl000009.result
index 002f68439534e2898a11d1c2c07b555abedbf24e..4a8057467f2dda5d54af9da45d52db986440550a 100644
--- a/mysql-test/r/rpl000009.result
+++ b/mysql-test/r/rpl000009.result
@@ -49,21 +49,48 @@ show databases;
 Database
 mysql
 test
+create database foo;
+create table foo.t1(n int, s char(20));
+insert into foo.t1 values (1, 'original foo.t1');
+create table foo.t3(n int, s char(20));
+insert into foo.t3 values (1, 'original foo.t3');
+create database foo2;
+create table foo2.t1(n int, s char(20));
+insert into foo2.t1 values (1, 'original foo2.t1');
+create database bar;
+create table bar.t1(n int, s char(20));
+insert into bar.t1 values (1, 'original bar.t1');
+create table bar.t3(n int, s char(20));
+insert into bar.t3 values (1, 'original bar.t3');
 load data from master;
 show databases;
 Database
 bar
 foo
+foo2
 mysql
 test
 use foo;
 show tables;
 Tables_in_foo
+t1
+t3
+select * from t1;
+n	s
+1	original foo.t1
+use foo2;
+show tables;
+Tables_in_foo2
+t1
+select * from t1;
+n	s
+1	original foo2.t1
 use bar;
 show tables;
 Tables_in_bar
 t1
 t2
+t3
 select * from bar.t1;
 n	s
 1	one bar
@@ -74,6 +101,9 @@ n	s
 11	eleven bar
 12	twelve bar
 13	thirteen bar
+select * from bar.t3;
+n	s
+1	original bar.t3
 insert into bar.t1 values (4, 'four bar');
 select * from bar.t1;
 n	s
@@ -81,5 +111,23 @@ n	s
 2	two bar
 3	three bar
 4	four bar
+insert into bar.t1 values(10, 'should be there');
+flush tables;
+load data from master;
+Error on delete of './bar/t1.MYI' (Errcode: 13)
+select * from bar.t1;
+n	s
+1	one bar
+2	two bar
+3	three bar
+4	four bar
+10	should be there
+load table bar.t1 from master;
+Table 't1' already exists
+drop table bar.t1;
+load table bar.t1 from master;
+start slave;
 drop database bar;
 drop database foo;
+drop database foo;
+drop database foo2;
diff --git a/mysql-test/t/rpl000009.test b/mysql-test/t/rpl000009.test
index 5f55355271a91c32b0141e564e2d341f930743d2..975cfbf9a658014adc8e9810234426994c3cdafc 100644
--- a/mysql-test/t/rpl000009.test
+++ b/mysql-test/t/rpl000009.test
@@ -60,16 +60,45 @@ sync_with_master;
 
 # This should show that the slave is empty at this point
 show databases;
+# Create foo and foo2 on slave; we expect that LOAD DATA FROM MASTER will
+# neither touch database foo nor foo2.
+create database foo;
+create table foo.t1(n int, s char(20));
+insert into foo.t1 values (1, 'original foo.t1');
+create table foo.t3(n int, s char(20));
+insert into foo.t3 values (1, 'original foo.t3');
+create database foo2;
+create table foo2.t1(n int, s char(20));
+insert into foo2.t1 values (1, 'original foo2.t1');
+# Create bar, and bar.t1, to check that it gets replaced,
+# and bar.t3 to check that it is not touched (there is no bar.t3 on master)
+create database bar;
+create table bar.t1(n int, s char(20));
+insert into bar.t1 values (1, 'original bar.t1');
+create table bar.t3(n int, s char(20));
+insert into bar.t3 values (1, 'original bar.t3');
+
 load data from master;
 
 # Now let's check if we have the right tables and the right data in them
 show databases;
 use foo;
-show tables;
+# LOAD DATA FROM MASTER uses only replicate_*_db rules to decide which databases
+# have to be copied. So it thinks "foo" has to be copied. Before 4.0.16 it would
+# first drop "foo", then create "foo". This "drop" is a bug; in that case t3
+# would disappear.
+# So here the effect of this bug (BUG#1248) would be to leave an empty "foo" on
+# the slave.
+show tables; # should be t1 & t3
+select * from t1; # should be slave's original
+use foo2;
+show tables; # should be t1
+select * from t1; # should be slave's original
 use bar;
-show tables;
+show tables; # should contain master's copied t1&t2, slave's original t3
 select * from bar.t1;
 select * from bar.t2;
+select * from bar.t3;
 
 # Now let's see if replication works
 connection master;
@@ -79,6 +108,26 @@ connection slave;
 sync_with_master;
 select * from bar.t1;
 
+# Check that LOAD DATA FROM MASTER reports the error if it can't drop a
+# table to be overwritten.
+insert into bar.t1 values(10, 'should be there');
+flush tables;
+system chmod 500 var/slave-data/bar/;
+--error 6
+load data from master;  # should fail (errno 13)
+system chmod 700 var/slave-data/bar/;
+select * from bar.t1; # should contain the row (10, ...)
+
+
+# Check that LOAD TABLE FROM MASTER fails if the table exists on slave
+--error 1050
+load table bar.t1 from master;
+drop table bar.t1;
+load table bar.t1 from master;
+
+# as LOAD DATA FROM MASTER failed it did not restart slave threads
+start slave;
+
 # Now time for cleanup
 connection master;
 drop database bar;
@@ -86,4 +135,5 @@ drop database foo;
 save_master_pos;
 connection slave;
 sync_with_master;
-
+drop database foo;
+drop database foo2;
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index dc3f3c87dde08276a1a4ad4d568722d09ad7d95d..8deb23e8586351a7318b97893fa0d687e50ac532 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -717,7 +717,8 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db,
       if (!tables_ok(thd, &table))
 	continue;
     }
-    if ((error= fetch_master_table(thd, db, table_name, mi, mysql)))
+    /* download master's table and overwrite slave's table */
+    if ((error= fetch_master_table(thd, db, table_name, mi, mysql, 1)))
       return error;
   }
   return 0;
@@ -819,8 +820,11 @@ int load_master_data(THD* thd)
       char* db = row[0];
 
       /*
-	Do not replicate databases excluded by rules
-	also skip mysql database - in most cases the user will
+	Do not replicate databases excluded by rules. We also test
+	replicate_wild_*_table rules (replicate_wild_ignore_table='db1.%' will
+	be considered as "ignore the 'db1' database as a whole, as it already
+	works for CREATE DATABASE and DROP DATABASE).
+	Also skip 'mysql' database - in most cases the user will
 	mess up and not exclude mysql database with the rules when
 	he actually means to - in this case, he is up for a surprise if
 	his priv tables get dropped and downloaded from master
@@ -830,14 +834,14 @@ int load_master_data(THD* thd)
       */
 
       if (!db_ok(db, replicate_do_db, replicate_ignore_db) ||
+          !db_ok_with_wild_table(db) ||
 	  !strcmp(db,"mysql"))
       {
 	*cur_table_res = 0;
 	continue;
       }
 
-      if (mysql_rm_db(thd, db, 1,1) ||
-	  mysql_create_db(thd, db, 0, 1))
+      if (mysql_create_db(thd, db, HA_LEX_CREATE_IF_NOT_EXISTS, 1))
       {
 	send_error(&thd->net, 0, 0);
 	cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
diff --git a/sql/slave.cc b/sql/slave.cc
index 1bc8dfc5b78b1e25aaec4f389f02d7e749511335..10d451a88bc1670fc3824f0c7b6934260332e51b 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -72,7 +72,7 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
 		      void* thread_killed_arg);
 static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
 static int create_table_from_dump(THD* thd, NET* net, const char* db,
-				  const char* table_name);
+				  const char* table_name, bool overwrite);
 static int check_master_version(MYSQL* mysql, MASTER_INFO* mi);
 
 
@@ -1033,12 +1033,22 @@ static int check_master_version(MYSQL* mysql, MASTER_INFO* mi)
   return 0;
 }
 
+/*
+  Used by fetch_master_table (used by LOAD TABLE tblname FROM MASTER and LOAD
+  DATA FROM MASTER). Drops the table (if 'overwrite' is true) and recreates it
+  from the dump. Honours replication inclusion/exclusion rules.
+
+  RETURN VALUES
+    0           success
+    1           error
+*/
 
 static int create_table_from_dump(THD* thd, NET* net, const char* db,
-				  const char* table_name)
+				  const char* table_name, bool overwrite)
 {
   ulong packet_len = my_net_read(net); // read create table statement
   char *query;
+  char* save_db;
   Vio* save_vio;
   HA_CHECK_OPT check_opt;
   TABLE_LIST tables;
@@ -1078,13 +1088,24 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
   thd->current_tablenr = 0;
   thd->query_error = 0;
   thd->net.no_send_ok = 1;
+
+  bzero((char*) &tables,sizeof(tables));
+  tables.db = (char*)db;
+  tables.alias= tables.real_name= (char*)table_name;
+  /* Drop the table if 'overwrite' is true */
+  if (overwrite && mysql_rm_table(thd,&tables,1)) /* drop if exists */
+  {
+    send_error(&thd->net);
+    sql_print_error("create_table_from_dump: failed to drop the table");
+    goto err;
+  }
   
-  /* we do not want to log create table statement */
+  /* Create the table. We do not want to log the "create table" statement */
   save_options = thd->options;
   thd->options &= ~(ulong) (OPTION_BIN_LOG);
   thd->proc_info = "Creating table from master dump";
   // save old db in case we are creating in a different database
-  char* save_db = thd->db;
+  save_db = thd->db;
   thd->db = (char*)db;
   mysql_parse(thd, thd->query, packet_len); // run create table
   thd->db = save_db;		// leave things the way the were before
@@ -1093,11 +1114,8 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
   if (thd->query_error)
     goto err;			// mysql_parse took care of the error send
 
-  bzero((char*) &tables,sizeof(tables));
-  tables.db = (char*)db;
-  tables.alias= tables.real_name= (char*)table_name;
-  tables.lock_type = TL_WRITE;
   thd->proc_info = "Opening master dump table";
+  tables.lock_type = TL_WRITE;
   if (!open_ltable(thd, &tables, TL_WRITE))
   {
     send_error(&thd->net,0,0);			// Send error from open_ltable
@@ -1107,10 +1125,11 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
   
   file = tables.table->file;
   thd->proc_info = "Reading master dump table data";
+  /* Copy the data file */
   if (file->net_read_dump(net))
   {
     net_printf(&thd->net, ER_MASTER_NET_READ);
-    sql_print_error("create_table_from_dump::failed in\
+    sql_print_error("create_table_from_dump: failed in\
  handler::net_read_dump()");
     goto err;
   }
@@ -1125,6 +1144,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
   */
   save_vio = thd->net.vio;
   thd->net.vio = 0;
+  /* Rebuild the index file from the copied data file (with REPAIR) */
   error=file->repair(thd,&check_opt) != 0;
   thd->net.vio = save_vio;
   if (error)
@@ -1137,7 +1157,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
 }
 
 int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
-		       MASTER_INFO *mi, MYSQL *mysql)
+		       MASTER_INFO *mi, MYSQL *mysql, bool overwrite)
 {
   int error= 1;
   const char *errmsg=0;
@@ -1169,9 +1189,10 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
     errmsg= "Failed on table dump request";
     goto err;
   }
+
   if (create_table_from_dump(thd, &mysql->net, db_name,
-			    table_name))
-    goto err;    // create_table_from_dump will have sent the error already
+			    table_name, overwrite))
+    goto err; // create_table_from_dump will have send_error already
   error = 0;
 
  err:
diff --git a/sql/slave.h b/sql/slave.h
index 67bf009763b5aff36daa6ce8d44cb6dd479f1102..f61891acc916685220633aeb1795be46f28e0bd4 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -384,9 +384,9 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
 int mysql_table_dump(THD* thd, const char* db,
 		     const char* tbl_name, int fd = -1);
 
-/* retrieve non-exitent table from master */
+/* retrieve table from master and copy to slave*/
 int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
-		       MASTER_INFO* mi, MYSQL* mysql);
+		       MASTER_INFO* mi, MYSQL* mysql, bool overwrite);
 
 int show_master_info(THD* thd, MASTER_INFO* mi);
 int show_binlog_info(THD* thd);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 4d010ac9a4b6a85c75c771c096a0b08a52c8c41c..0c4e3cad7638a6a68c71b2866b5a2fb65755f04b 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1568,9 +1568,12 @@ mysql_execute_command(void)
 	goto error;
     }
     LOCK_ACTIVE_MI;
-    // fetch_master_table will send the error to the client on failure
+    /*
+      fetch_master_table will send the error to the client on failure.
+      Give error if the table already exists.
+    */
     if (!fetch_master_table(thd, tables->db, tables->real_name,
-			    active_mi, 0))
+			    active_mi, 0, 0))
     {
       send_ok(&thd->net);
     }