diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared
index 50dedebe1192b4e1c8cc9d7a455eb27b05913a0d..204c833dd21cd0f96cf45b1786eaea7ab2ce3857 100644
--- a/libmysql/Makefile.shared
+++ b/libmysql/Makefile.shared
@@ -96,7 +96,8 @@ clean-local:
 	      `echo $(sql_cmn_objects) | sed "s;\.lo;.c;g"` \
 	       $(CHARSET_SRCS) $(CHARSET_OBJS) \
 	       $(mystringsextra) $(mysysheaders) $(vioheaders)\
-	       ../linked_client_sources net.c
+	       ../linked_libmysql_sources ../linked_libmysql_r_sources \
+               net.c
 
 conf_to_src_SOURCES = conf_to_src.c
 conf_to_src_LDADD=
diff --git a/mysql-test/r/rpl_deadlock.result b/mysql-test/r/rpl_deadlock.result
index 809b7950add39b211be99c6f4881ca310b38f95f..732979eae0a5ba9bd11267eca339ee1c4fe29454 100644
--- a/mysql-test/r/rpl_deadlock.result
+++ b/mysql-test/r/rpl_deadlock.result
@@ -8,6 +8,9 @@ create table t1 (a int not null, key(a)) engine=innodb;
 create table t2 (a int not null, key(a)) engine=innodb;
 create table t3 (a int) engine=innodb;
 create table t4 (a int) engine=innodb;
+show variables like 'slave_transaction_retries';
+Variable_name	Value
+slave_transaction_retries	0
 show create table t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
@@ -20,6 +23,9 @@ t2	CREATE TABLE `t2` (
   `a` int(11) NOT NULL,
   KEY `a` (`a`)
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1
+show variables like 'slave_transaction_retries';
+Variable_name	Value
+slave_transaction_retries	2
 stop slave;
 begin;
 insert into t3 select * from t2 for update;
diff --git a/mysql-test/t/rpl_deadlock.test b/mysql-test/t/rpl_deadlock.test
index a196495e83454a7fb1bbc571e8cc4b832f54bb5f..800ff319ba087fbd6a563c68197a68c453fcfdc2 100644
--- a/mysql-test/t/rpl_deadlock.test
+++ b/mysql-test/t/rpl_deadlock.test
@@ -7,6 +7,8 @@
 # (Guilhem) have seen the test manage to provoke lock wait timeout
 # error but not deadlock error; that is ok as code deals with the two
 # errors in exactly the same way.
+# We don't 'show status like 'slave_retried_transactions'' because this
+# is not repeatable (depends on sleeps).
 
 source include/have_innodb.inc;
 source include/master-slave.inc;
@@ -16,10 +18,12 @@ create table t1 (a int not null, key(a)) engine=innodb;
 create table t2 (a int not null, key(a)) engine=innodb;
 create table t3 (a int) engine=innodb;
 create table t4 (a int) engine=innodb;
+show variables like 'slave_transaction_retries';
 sync_slave_with_master;
 
 show create table t1;
 show create table t2;
+show variables like 'slave_transaction_retries';
 stop slave;
 
 # 1) Test deadlock
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index ecaa7ace841075b2106222ddbc42ffc49349c370..ffa9be3a06e908436dd4eb8e40ead5d620989617 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3134,8 +3134,17 @@ we force server id to 2, but this MySQL server will not act as a slave.");
 #endif
   if (opt_bootstrap) /* If running with bootstrap, do not start replication. */
     opt_skip_slave_start= 1;
-  /* init_slave() must be called after the thread keys are created */
-  init_slave();
+  /*
+    init_slave() must be called after the thread keys are created.
+    Some parts of the code (e.g. SHOW STATUS LIKE 'slave_running' and other
+    places) assume that active_mi != 0, so let's fail if it's 0 (out of
+    memory); a message has already been printed.
+  */
+  if (init_slave() && !active_mi)
+  {
+    end_thr_alarm(1);				// Don't allow alarms
+    unireg_abort(1);
+  }
 
   if (opt_bootstrap)
   {
@@ -5689,7 +5698,8 @@ struct show_var_st status_vars[]= {
   {"Select_range_check",       (char*) offsetof(STATUS_VAR, select_range_check_count), SHOW_LONG_STATUS},
   {"Select_scan",	       (char*) offsetof(STATUS_VAR, select_scan_count), SHOW_LONG_STATUS},
   {"Slave_open_temp_tables",   (char*) &slave_open_temp_tables, SHOW_LONG},
-  {"Slave_running",            (char*) 0, SHOW_SLAVE_RUNNING},
+  {"Slave_running",            (char*) 0,                       SHOW_SLAVE_RUNNING},
+  {"Slave_retried_transactions",(char*) 0,                      SHOW_SLAVE_RETRIED_TRANS},
   {"Slow_launch_threads",      (char*) &slow_launch_threads,    SHOW_LONG},
   {"Slow_queries",             (char*) offsetof(STATUS_VAR, long_query_count), SHOW_LONG_STATUS},
   {"Sort_merge_passes",	       (char*) offsetof(STATUS_VAR, filesort_merge_passes), SHOW_LONG_STATUS},
diff --git a/sql/slave.cc b/sql/slave.cc
index c92350f4a2fb25eead6869e89f73b8a8c13bd7c7..ebf87660a0e060179e874144b8826e3b29f861d6 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -27,6 +27,7 @@
 #include <my_dir.h>
 #include <sql_common.h>
 
+#define MAX_SLAVE_RETRY_PAUSE 5
 bool use_slave_mask = 0;
 MY_BITMAP slave_error_mask;
 
@@ -2528,7 +2529,7 @@ st_relay_log_info::st_relay_log_info()
    ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0),
    abort_pos_wait(0), slave_run_id(0), sql_thd(0), last_slave_errno(0),
    inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
-   until_log_pos(0)
+   until_log_pos(0), retried_trans(0)
 {
   group_relay_log_name[0]= event_relay_log_name[0]=
     group_master_log_name[0]= 0;
@@ -3261,9 +3262,8 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
           init_master_info()).
           b) init_relay_log_pos(), because the BEGIN may be an older relay log.
         */
-        if (rli->trans_retries--)
+        if (rli->trans_retries < slave_trans_retries)
         {
-          sql_print_information("Slave SQL thread retries transaction");
           if (init_master_info(rli->mi, 0, 0, 0, SLAVE_SQL))
             sql_print_error("Failed to initialize the master info structure");
           else if (init_relay_log_pos(rli,
@@ -3275,8 +3275,16 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
           else
           {
             exec_res= 0;
-            sleep(2); // chance for concurrent connection to get more locks
-          }
+	    /* chance for concurrent connection to get more locks */
+            safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
+		       (CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);
+            pthread_mutex_lock(&rli->data_lock); // because of SHOW STATUS
+	    rli->trans_retries++;
+            rli->retried_trans++;
+            pthread_mutex_unlock(&rli->data_lock);
+            DBUG_PRINT("info", ("Slave retries transaction "
+                                "rli->trans_retries: %lu", rli->trans_retries));
+	  }
         }
         else
           sql_print_error("Slave SQL thread retried transaction %lu time(s) "
@@ -3285,8 +3293,8 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
                           slave_trans_retries);
       }
       if (!((thd->options & OPTION_BEGIN) && opt_using_transactions))
-        rli->trans_retries= slave_trans_retries; // restart from fresh
-    }
+         rli->trans_retries= 0; // restart from fresh
+     }
     return exec_res;
   }
   else
@@ -3701,7 +3709,7 @@ slave_begin:
   pthread_mutex_lock(&rli->log_space_lock);
   rli->ignore_log_space_limit= 0;
   pthread_mutex_unlock(&rli->log_space_lock);
-  rli->trans_retries= slave_trans_retries; // start from "no error"
+  rli->trans_retries= 0; // start from "no error"
 
   if (init_relay_log_pos(rli,
 			 rli->group_relay_log_name,
diff --git a/sql/slave.h b/sql/slave.h
index bc41cd4decaca10baf5b6561b21066d3ae406ccb..c41234ab2ed1f18b111abbea25c70a3a58de2a3c 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -293,7 +293,14 @@ typedef struct st_relay_log_info
   } until_log_names_cmp_result;
 
   char cached_charset[6];
-  ulong trans_retries;
+  /*
+    trans_retries varies between 0 to slave_transaction_retries and counts how
+    many times the slave has retried the present transaction; gets reset to 0
+    when the transaction finally succeeds. retried_trans is a cumulative
+    counter: how many times the slave has retried a transaction (any) since
+    slave started.
+  */
+  ulong trans_retries, retried_trans;
 
   st_relay_log_info();
   ~st_relay_log_info();
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index fadc445e85d291dc302a0f28756efb6f957ed0fd..9f7aaa70a090902eb0fc21a56fcc072162120de2 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1331,6 +1331,19 @@ static bool show_status_array(THD *thd, const char *wild,
           pthread_mutex_unlock(&LOCK_active_mi);
           break;
         }
+        case SHOW_SLAVE_RETRIED_TRANS:
+        {
+          /*
+            TODO: in 5.1 with multimaster, have one such counter per line in SHOW
+            SLAVE STATUS, and have the sum over all lines here.
+          */
+	  pthread_mutex_lock(&LOCK_active_mi);
+          pthread_mutex_lock(&active_mi->rli.data_lock);
+	  end= int10_to_str(active_mi->rli.retried_trans, buff, 10);
+          pthread_mutex_unlock(&active_mi->rli.data_lock);
+	  pthread_mutex_unlock(&LOCK_active_mi);
+	  break;
+        }
 #endif /* HAVE_REPLICATION */
         case SHOW_OPENTABLES:
           end= int10_to_str((long) cached_tables(), buff, 10);
diff --git a/sql/structs.h b/sql/structs.h
index cbc7161ee20cc80c4b94c847e17775d97163b52e..7a70bfc0f4fa5172f63bd1e6799fa87f387faa7a 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -182,7 +182,7 @@ enum SHOW_TYPE
   SHOW_SSL_CTX_SESS_TIMEOUTS, SHOW_SSL_CTX_SESS_CACHE_FULL,
   SHOW_SSL_GET_CIPHER_LIST,
 #endif /* HAVE_OPENSSL */
-  SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING,
+  SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING, SHOW_SLAVE_RETRIED_TRANS,
   SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG,
   SHOW_LONG_STATUS, SHOW_LONG_CONST_STATUS
 };