diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result
index c7be93b0fd7f84f1500024c7ec89512cc57fef25..766e43b229988e9f2123800d20c5ac383ac4a6b9 100644
--- a/mysql-test/r/group_min_max.result
+++ b/mysql-test/r/group_min_max.result
@@ -1657,6 +1657,44 @@ a
 b
 c
 d
+select distinct a1,a1 from t1;
+a1	a1
+a	a
+b	b
+c	c
+d	d
+select distinct a2,a1,a2,a1 from t1;
+a2	a1	a2	a1
+a	a	a	a
+b	a	b	a
+a	b	a	b
+b	b	b	b
+a	c	a	c
+b	c	b	c
+a	d	a	d
+b	d	b	d
+select distinct t1.a1,t2.a1 from t1,t2;
+a1	a1
+a	a
+b	a
+c	a
+d	a
+a	b
+b	b
+c	b
+d	b
+a	c
+b	c
+c	c
+d	c
+a	d
+b	d
+c	d
+d	d
+a	e
+b	e
+c	e
+d	e
 explain select distinct a1,a2,b from t1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	range	NULL	idx_t1_1	147	NULL	17	Using index for group-by
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index 1c2f4662ef1e9914c1337693c8897a87946bc77e..1182c3d3569ac523240603aea5f9b06bdda406d4 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -466,4 +466,32 @@ ERROR 70100: Query execution was interrupted
 call bug6807()|
 ERROR 70100: Query execution was interrupted
 drop procedure bug6807|
+drop procedure if exists bug8776_1|
+drop procedure if exists bug8776_2|
+drop procedure if exists bug8776_3|
+drop procedure if exists bug8776_4|
+create procedure bug8776_1()
+begin
+declare continue handler for sqlstate '42S0200test' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '42S0200test'
+create procedure bug8776_2()
+begin
+declare continue handler for sqlstate '4200' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '4200'
+create procedure bug8776_3()
+begin
+declare continue handler for sqlstate '420000' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '420000'
+create procedure bug8776_4()
+begin
+declare continue handler for sqlstate '42x00' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '42x00'
 drop table t1|
diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test
index b42125566d53b47ade1402a47ce138bc6701c206..d85b33958537fef7566535ecb8b2a6366691b66c 100644
--- a/mysql-test/t/group_min_max.test
+++ b/mysql-test/t/group_min_max.test
@@ -475,11 +475,15 @@ select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121
 select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
 select distinct b from t2 where (a2 >= 'b') and (b = 'a');
 
--- BUG 6303
+-- BUG #6303
 select distinct t_00.a1
 from t1 t_00
 where exists ( select * from t2 where a1 = t_00.a1 );
 
+-- BUG #8532 - SELECT DISTINCT a, a causes server to crash
+select distinct a1,a1 from t1;
+select distinct a2,a1,a2,a1 from t1;
+select distinct t1.a1,t2.a1 from t1,t2;
 
 --
 -- DISTINCT queries with GROUP-BY
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index 594daf66fcb039c60bea4c58f99139b5203fef4f..0f775958d7a9d008373516c16c6bf29168e6a9cb 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -641,6 +641,44 @@ call bug6807()|
 
 drop procedure bug6807|
 
+#
+# BUG#876: Stored Procedures: Invalid SQLSTATE is allowed in 
+#          a DECLARE ? HANDLER FOR stmt.
+#
+--disable_warnings
+drop procedure if exists bug8776_1|
+drop procedure if exists bug8776_2|
+drop procedure if exists bug8776_3|
+drop procedure if exists bug8776_4|
+--enable_warnings
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_1()
+begin
+  declare continue handler for sqlstate '42S0200test' begin end;
+  begin end;
+end|
+
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_2()
+begin
+  declare continue handler for sqlstate '4200' begin end;
+  begin end;
+end|
+
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_3()
+begin
+  declare continue handler for sqlstate '420000' begin end;
+  begin end;
+end|
+
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_4()
+begin
+  declare continue handler for sqlstate '42x00' begin end;
+  begin end;
+end|
+
 
 drop table t1|
 
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 12e5c60312b4ca8d275a1e7b221c620ca7f744db..812d5a41cbcc417ab6ad3bf2097558d75c40c61c 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -6878,6 +6878,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
   SEL_ARG *cur_index_tree= NULL;
   ha_rows cur_quick_prefix_records= 0;
   uint cur_param_idx;
+  key_map cur_used_key_parts;
 
   for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ;
        cur_index_info++, cur_index++)
@@ -6925,17 +6926,25 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
     else if (join->select_distinct)
     {
       select_items_it.rewind();
+      cur_used_key_parts.clear_all();
       while ((item= select_items_it++))
       {
         item_field= (Item_field*) item; /* (SA5) already checked above. */
         /* Find the order of the key part in the index. */
         key_part_nr= get_field_keypart(cur_index_info, item_field->field);
+        /*
+          Check if this attribute was already present in the select list.
+          If it was present, then its corresponding key part was alredy used.
+        */
+        if (cur_used_key_parts.is_set(key_part_nr))
+          continue;
         if (key_part_nr < 1 || key_part_nr > join->fields_list.elements)
           goto next_index;
         cur_part= cur_index_info->key_part + key_part_nr - 1;
         cur_group_prefix_len+= cur_part->store_length;
+        cur_used_key_parts.set_bit(key_part_nr);
+        ++cur_group_key_parts;
       }
-      cur_group_key_parts= join->fields_list.elements;
     }
     else
       DBUG_ASSERT(FALSE);
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 5757510bfb451ad96078b5cda8d9e1546cf4da98..ba4ef70486ba7facd3a81fcca7c7283d15d083e2 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5326,3 +5326,5 @@ ER_PROC_AUTO_REVOKE_FAIL
 	eng "Failed to revoke all privileges to dropped routine"
 ER_DATA_TOO_LONG 22001
 	eng "Data too long for column '%s' at row %ld"
+ER_SP_BAD_SQLSTATE 42000
+	eng "Bad SQLSTATE: '%s'"
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index 7176498f276a426d6422c3fb265a322f5e81b0e4..15d3f87ff29338b0bb3c5face8326048fa52402e 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -26,6 +26,30 @@
 #include "sp_pcontext.h"
 #include "sp_head.h"
 
+/*
+ * Sanity check for SQLSTATEs. Will not check if it's really an existing
+ * state (there are just too many), but will check length and bad characters.
+ * Returns TRUE if it's ok, FALSE if it's bad.
+ */
+bool
+sp_cond_check(LEX_STRING *sqlstate)
+{
+  int i;
+  const char *p;
+
+  if (sqlstate->length != 5)
+    return FALSE;
+  for (p= sqlstate->str, i= 0 ; i < 5 ; i++)
+  {
+    char c = p[i];
+
+    if ((c < '0' || '9' < c) &&
+	(c < 'A' || 'Z' < c))
+      return FALSE;
+  }
+  return TRUE;
+}
+
 sp_pcontext::sp_pcontext(sp_pcontext *prev)
   : Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0),
     m_handlers(0), m_parent(prev)
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 66f631f49386d0fade33480e833f917a00d5ce84..42d8140b78c1074daf7d1f6d4328b50c7d9d2ca4 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -60,6 +60,12 @@ typedef struct sp_cond_type
   uint mysqlerr;
 } sp_cond_type_t;
 
+/* Sanity check for SQLSTATEs. Will not check if it's really an existing
+ * state (there are just too many), but will check length bad characters.
+ */
+extern bool
+sp_cond_check(LEX_STRING *sqlstate);
+
 typedef struct sp_cond
 {
   LEX_STRING name;
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 8c486566fa643fbdb03f254a62689873e603fb70..95417c9face4a73aba9199ca0fcad737efd4d660 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1274,6 +1274,7 @@ bool mysql_show_binlog_events(THD* thd)
   DBUG_ENTER("show_binlog_events");
   List<Item> field_list;
   const char *errmsg = 0;
+  bool ret = TRUE;
   IO_CACHE log;
   File file = -1;
   Format_description_log_event *description_event= new
@@ -1376,6 +1377,8 @@ bool mysql_show_binlog_events(THD* thd)
     pthread_mutex_unlock(log_lock);
   }
 
+  ret= FALSE;
+
 err:
   delete description_event;
   if (file >= 0)
@@ -1395,7 +1398,7 @@ bool mysql_show_binlog_events(THD* thd)
   pthread_mutex_lock(&LOCK_thread_count);
   thd->current_linfo = 0;
   pthread_mutex_unlock(&LOCK_thread_count);
-  DBUG_RETURN(TRUE);
+  DBUG_RETURN(ret);
 }
 
 
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 45c3e94f0ffc9c03cb23e1aaa7449d643850a901..a69b6a96982cfba5bf583ee7e2c35b9f75b76f96 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1760,13 +1760,15 @@ sp_cond:
 	  }
 	| SQLSTATE_SYM opt_value TEXT_STRING_literal
 	  {		/* SQLSTATE */
-	    uint len= ($3.length < sizeof($$->sqlstate)-1 ?
-                       $3.length : sizeof($$->sqlstate)-1);
-
+	    if (!sp_cond_check(&$3))
+	    {
+	      my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str);
+	      YYABORT;
+	    }
 	    $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
 	    $$->type= sp_cond_type_t::state;
-	    memcpy($$->sqlstate, $3.str, len);
-	    $$->sqlstate[len]= '\0';
+	    memcpy($$->sqlstate, $3.str, 5);
+	    $$->sqlstate[5]= '\0';
 	  }
 	;