diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result
index e24c3179a0cb12dc8d032f8035b181c0ed0d8ed8..b49ca3a6c2f246bf4f0559e2a486f9bdd89b0580 100644
--- a/mysql-test/r/insert_select.result
+++ b/mysql-test/r/insert_select.result
@@ -66,3 +66,17 @@ INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip)
 SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM crash2
 WHERE numeropost=9 ORDER BY numreponse ASC;
 DROP TABLE IF EXISTS crash1,crash2;
+drop table if exists t1;
+drop table if exists t2;
+create table t1(a int, unique(a));
+insert into t1 values(2);
+create table t2(a int);
+insert into t2 values(1),(2);
+reset master;
+insert into t1 select * from t2;
+Duplicate entry '2' for key 1
+show binlog events;
+Log_name	Pos	Event_type	Server_id	Orig_log_pos	Info
+master-bin.001	4	Start	1	4	Server ver: VERSION, Binlog ver: 3
+master-bin.001	79	Query	1	79	use test; insert into t1 select * from t2
+drop table t1, t2;
diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result
index 70f9ff0de0f45e7825ce6f649cd5822b02afdf04..0065d83f16938f63d53b6a9afb7aaa7b926f58e1 100644
--- a/mysql-test/r/rpl_insert_id.result
+++ b/mysql-test/r/rpl_insert_id.result
@@ -41,3 +41,31 @@ b	c
 6	11
 drop table t1;
 drop table t2;
+create table t1(a int auto_increment, key(a));
+create table t2(b int auto_increment, c int, key(b));
+insert into t1 values (10);
+insert into t1 values (null),(null),(null);
+insert into t2 values (5,0);
+insert into t2 (c) select * from t1;
+select * from t2;
+b	c
+5	0
+6	10
+7	11
+8	12
+9	13
+select * from t1;
+a
+10
+11
+12
+13
+select * from t2;
+b	c
+5	0
+6	10
+7	11
+8	12
+9	13
+drop table t1;
+drop table t2;
diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test
index 42f65858d77a1c5618f510166122fc65c69f1817..695f891f678f74ca9a7cf6efc5e32375d7f364ae 100644
--- a/mysql-test/t/insert_select.test
+++ b/mysql-test/t/insert_select.test
@@ -68,3 +68,22 @@ WHERE numeropost=9 ORDER BY numreponse ASC;
 
 DROP TABLE IF EXISTS crash1,crash2;
 
+
+# Addendum by Guilhem:
+# Check if a partly-completed INSERT SELECT in a MyISAM table goes
+# into the binlog
+drop table if exists t1;
+drop table if exists t2;
+create table t1(a int, unique(a));
+insert into t1 values(2);
+create table t2(a int);
+insert into t2 values(1),(2);
+reset master;
+--error 1062
+insert into t1 select * from t2;
+# The above should produce an error, but still be in the binlog;
+# verify the binlog :
+let $VERSION=`select version()`;
+--replace_result $VERSION VERSION
+show binlog events;
+drop table t1, t2;
diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test
index a9e4de21e5c04018512d89f7925b1399d76c951d..26d5d3a9ed22c8939266b2046032508fae3b7ac0 100644
--- a/mysql-test/t/rpl_insert_id.test
+++ b/mysql-test/t/rpl_insert_id.test
@@ -36,6 +36,24 @@ sync_with_master;
 select * from t1;
 select * from t2;
 connection master;
+
+# check if INSERT SELECT in auto_increment is well replicated (bug #490)
+
+drop table t1;
+drop table t2;
+create table t1(a int auto_increment, key(a));
+create table t2(b int auto_increment, c int, key(b));
+insert into t1 values (10);
+insert into t1 values (null),(null),(null);
+insert into t2 values (5,0);
+insert into t2 (c) select * from t1;
+select * from t2;
+save_master_pos;
+connection slave;
+sync_with_master;
+select * from t1;
+select * from t2;
+connection master;
 drop table t1;
 drop table t2;
 save_master_pos;
diff --git a/sql/slave.cc b/sql/slave.cc
index e6215356ad127e22c4967fd8064985c3838292b2..b620603dc6337cc274701939c042130fc10c800d 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1322,6 +1322,8 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
          !rli->ignore_log_space_limit)
   {
     pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
+    /* Re-acquire the mutex as pthread_cond_wait released it */
+    pthread_mutex_lock(&rli->log_space_lock);
   }
   thd->proc_info = save_proc_info;
   pthread_mutex_unlock(&rli->log_space_lock);
@@ -2028,7 +2030,11 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
   Log_event * ev = next_event(rli);
   DBUG_ASSERT(rli->sql_thd==thd);
   if (sql_slave_killed(thd,rli))
+  {
+    /* do not forget to free ev ! */
+    if (ev) delete ev;
     return 1;
+  }
   if (ev)
   {
     int type_code = ev->get_type_code();
@@ -2302,6 +2308,18 @@ reconnect done to recover from failed read");
 	goto err;
       }
       flush_master_info(mi);
+      /*
+        See if the relay logs take too much space.
+        We don't lock mi->rli.log_space_lock here; this dirty read saves time
+        and does not introduce any problem:
+        - if mi->rli.ignore_log_space_limit is 1 but becomes 0 just after (so
+        the clean value is 0), then we are reading only one more event as we
+        should, and we'll block only at the next event. No big deal.
+        - if mi->rli.ignore_log_space_limit is 0 but becomes 1 just after (so
+        the clean value is 1), then we are going into wait_for_relay_log_space()
+        for no reason, but this function will do a clean read, notice the clean
+        value and exit immediately.
+      */
       if (mi->rli.log_space_limit && mi->rli.log_space_limit <
 	  mi->rli.log_space_total &&
           !mi->rli.ignore_log_space_limit)
@@ -2416,7 +2434,9 @@ extern "C" pthread_handler_decl(handle_slave_sql,arg)
   rli->pending = 0;
 
   //tell the I/O thread to take relay_log_space_limit into account from now on
+  pthread_mutex_lock(&rli->log_space_lock);
   rli->ignore_log_space_limit= 0;
+  pthread_mutex_unlock(&rli->log_space_lock);
 
   if (init_relay_log_pos(rli,
 			 rli->relay_log_name,
@@ -3122,9 +3142,14 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
         pthread_mutex_lock(&rli->log_space_lock);
         // prevent the I/O thread from blocking next times
         rli->ignore_log_space_limit= 1; 
-        // If the I/O thread is blocked, unblock it
-        pthread_cond_broadcast(&rli->log_space_cond);
+        /*
+          If the I/O thread is blocked, unblock it.
+          Ok to broadcast after unlock, because the mutex is only destroyed in
+          ~st_relay_log_info(), i.e. when rli is destroyed, and rli will not be
+          destroyed before we exit the present function.
+        */
         pthread_mutex_unlock(&rli->log_space_lock);
+        pthread_cond_broadcast(&rli->log_space_cond);
         // Note that wait_for_update unlocks lock_log !
         rli->relay_log.wait_for_update(rli->sql_thd);
         // re-acquire data lock since we released it earlier
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 33a13fabdc68ff1fc32f18d98c595de92124f4fc..167ccf974c7d2f88201650c60de2046b2cad1235 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1350,6 +1350,24 @@ void select_insert::send_error(uint errcode,const char *err)
   ::send_error(&thd->net,errcode,err);
   table->file->extra(HA_EXTRA_NO_CACHE);
   table->file->activate_all_index(thd);
+  /* 
+     If at least one row has been inserted/modified and will stay in the table
+     (the table doesn't have transactions) (example: we got a duplicate key
+     error while inserting into a MyISAM table) we must write to the binlog (and
+     the error code will make the slave stop).
+  */
+  if ((info.copied || info.deleted) && !table->file->has_transactions())
+  {
+    if (last_insert_id)
+      thd->insert_id(last_insert_id);		// For binary log
+    mysql_update_log.write(thd,thd->query,thd->query_length);
+    if (mysql_bin_log.is_open())
+    {
+      Query_log_event qinfo(thd, thd->query, thd->query_length,
+                            table->file->has_transactions());
+      mysql_bin_log.write(&qinfo);
+    }
+  }
   ha_rollback_stmt(thd);
   if (info.copied || info.deleted)
   {
@@ -1365,7 +1383,10 @@ bool select_insert::send_eof()
     error=table->file->activate_all_index(thd);
   table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
 
+  if (last_insert_id)
+    thd->insert_id(last_insert_id);		// For binary log
   /* Write to binlog before commiting transaction */
+  mysql_update_log.write(thd,thd->query,thd->query_length);
   if (mysql_bin_log.is_open())
   {
     Query_log_event qinfo(thd, thd->query, thd->query_length,
@@ -1393,10 +1414,7 @@ bool select_insert::send_eof()
     else
       sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted,
 	      thd->cuted_fields);
-    if (last_insert_id)
-      thd->insert_id(last_insert_id);		// For update log
     ::send_ok(&thd->net,info.copied+info.deleted,last_insert_id,buff);
-    mysql_update_log.write(thd,thd->query,thd->query_length);
     return 0;
   }
 }