diff --git a/mysql-test/r/join_cache.result b/mysql-test/r/join_cache.result
index be579c9240f33accff9fea64412a392c09f4092b..8372f68fde05e699ae2557f09b7ef329f722c785 100644
--- a/mysql-test/r/join_cache.result
+++ b/mysql-test/r/join_cache.result
@@ -5179,4 +5179,51 @@ a	b
 SET SESSION join_cache_level = DEFAULT;
 SET optimizer_switch=@tmp887479_optimizer_switch;
 DROP TABLE t1,t2;
+#
+# Bug #899777: join_cache_level=4 + semijoin=on 
+#
+CREATE TABLE t1 (a int, b int, c int, UNIQUE INDEX idx (a));
+INSERT INTO t1 VALUES (1,8,6), (2,2,8);
+CREATE TABLE t2 (a int, b int, c int, UNIQUE INDEX idx (a));
+INSERT INTO t2 VALUES (1,8,6), (2,2,8);
+CREATE TABLE t3 (a int, b int, c int, UNIQUE INDEX idx (a));
+INSERT INTO t3 VALUES (1,8,6), (2,2,8);
+CREATE TABLE t4 (a int, b int, c int, UNIQUE INDEX idx (a));
+INSERT INTO t4 VALUES (1,8,6), (2,2,8);
+SET @tmp_optimizer_switch=@@optimizer_switch;
+SET SESSION optimizer_switch='semijoin=on';
+SET SESSION optimizer_switch='semijoin_with_cache=on';
+SET SESSION join_cache_level=1;
+EXPLAIN 
+SELECT t1.* FROM t1,t2
+WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b)
+AND t1.a = 1;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	const	idx	idx	5	const	1	
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	
+1	PRIMARY	t3	ALL	NULL	NULL	NULL	NULL	2	Using where; Start temporary; Using join buffer (flat, BNL join)
+1	PRIMARY	t4	ALL	NULL	NULL	NULL	NULL	2	Using where; End temporary; Using join buffer (flat, BNL join)
+SELECT t1.* FROM t1,t2
+WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b)
+AND t1.a = 1;
+a	b	c
+1	8	6
+SET SESSION join_cache_level=4;
+EXPLAIN 
+SELECT t1.* FROM t1,t2
+WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b)
+AND t1.a = 1;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	PRIMARY	t1	const	idx	idx	5	const	1	
+1	PRIMARY	t2	ALL	NULL	NULL	NULL	NULL	2	Using where
+1	PRIMARY	t3	hash_ALL	NULL	#hash#$hj	5	const	2	Using where; Start temporary; Using join buffer (flat, BNLH join)
+1	PRIMARY	t4	hash_ALL	NULL	#hash#$hj	10	const,test.t2.b	2	Using where; End temporary; Using join buffer (incremental, BNLH join)
+SELECT t1.* FROM t1,t2
+WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b)
+AND t1.a = 1;
+a	b	c
+1	8	6
+SET SESSION join_cache_level = DEFAULT;
+SET optimizer_switch=@tmp_optimizer_switch;
+DROP TABLE t1,t2,t3,t4;
 set @@optimizer_switch=@save_optimizer_switch;
diff --git a/mysql-test/t/join_cache.test b/mysql-test/t/join_cache.test
index 530528ead2c1d24fe184305a6514a4c8d8bb7ac7..66381150ede11e128ca1588a948fccfad560fd17 100644
--- a/mysql-test/t/join_cache.test
+++ b/mysql-test/t/join_cache.test
@@ -3254,5 +3254,45 @@ SET optimizer_switch=@tmp887479_optimizer_switch;
 
 DROP TABLE t1,t2;
 
+--echo #
+--echo # Bug #899777: join_cache_level=4 + semijoin=on 
+--echo #
+
+CREATE TABLE t1 (a int, b int, c int, UNIQUE INDEX idx (a));
+INSERT INTO t1 VALUES (1,8,6), (2,2,8);
+CREATE TABLE t2 (a int, b int, c int, UNIQUE INDEX idx (a));
+INSERT INTO t2 VALUES (1,8,6), (2,2,8);
+CREATE TABLE t3 (a int, b int, c int, UNIQUE INDEX idx (a));
+INSERT INTO t3 VALUES (1,8,6), (2,2,8);
+CREATE TABLE t4 (a int, b int, c int, UNIQUE INDEX idx (a));
+INSERT INTO t4 VALUES (1,8,6), (2,2,8);
+
+SET @tmp_optimizer_switch=@@optimizer_switch;
+SET SESSION optimizer_switch='semijoin=on';
+SET SESSION optimizer_switch='semijoin_with_cache=on';
+
+SET SESSION join_cache_level=1;
+EXPLAIN 
+SELECT t1.* FROM t1,t2
+  WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b)
+        AND t1.a = 1;
+SELECT t1.* FROM t1,t2
+  WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b)
+        AND t1.a = 1;
+
+SET SESSION join_cache_level=4;
+EXPLAIN 
+SELECT t1.* FROM t1,t2
+  WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b)
+        AND t1.a = 1;
+SELECT t1.* FROM t1,t2
+  WHERE (t1.b,t2.b) IN (SELECT t3.b,t4.b FROM t3,t4 WHERE t4.c=t3.b)
+        AND t1.a = 1;
+
+SET SESSION join_cache_level = DEFAULT;
+SET optimizer_switch=@tmp_optimizer_switch;
+
+DROP TABLE t1,t2,t3,t4;
+
 # this must be the last command in the file
 set @@optimizer_switch=@save_optimizer_switch;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 6fbba67e1564fb0103748d28737bdbeaa072ae9d..b0fd09b7f243c42c8cbec12c6078bdfe6dc8e80f 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -7183,10 +7183,26 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
 
   do
   {
-    if (!(~used_tables & keyuse->used_tables) &&
-	(first_keyuse || keyuse->keypart != (keyuse-1)->keypart))
-      key_parts++;
-    first_keyuse= FALSE;
+    if (!(~used_tables & keyuse->used_tables))
+    {
+      if (first_keyuse)
+      {
+        key_parts++;
+        first_keyuse= FALSE;
+      }
+      else
+      {
+        KEYUSE *curr= org_keyuse;
+        for( ; curr < keyuse; curr++)
+        {
+          if (curr->keypart == keyuse->keypart &&
+              !(~used_tables & curr->used_tables))
+            break;
+        }
+        if (curr == keyuse)
+           key_parts++;
+      }
+    }
     keyuse++;
   } while (keyuse->table == table && keyuse->is_for_hash_join());
   if (!key_parts)
@@ -7211,15 +7227,31 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
   keyuse= org_keyuse;
   do
   {
-    if (!(~used_tables & keyuse->used_tables) &&
-        (first_keyuse || keyuse->keypart != (keyuse-1)->keypart))
-    {
-      Field *field= table->field[keyuse->keypart];
-      uint fieldnr= keyuse->keypart+1;
-      table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr);
-      first_keyuse= FALSE;
-      key_part_info++;
+    if (!(~used_tables & keyuse->used_tables))
+    { 
+      bool add_key_part= TRUE;
+      if (!first_keyuse)
+      {
+        for(KEYUSE *curr= org_keyuse; curr < keyuse; curr++)
+        {
+          if (curr->keypart == keyuse->keypart &&
+              !(~used_tables & curr->used_tables))
+	  {
+            keyuse->keypart= NO_KEYPART;
+            add_key_part= FALSE;
+            break;
+          }
+        }
+      }
+      if (add_key_part)
+      {
+        Field *field= table->field[keyuse->keypart];
+        uint fieldnr= keyuse->keypart+1;
+        table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr);
+        key_part_info++;
+      }
     }
+    first_keyuse= FALSE;
     keyuse++;
   } while (keyuse->table == table && keyuse->is_for_hash_join());
 
@@ -7302,8 +7334,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
       {
         if  (are_tables_local(j, keyuse->val->used_tables()))
         {
-          if ((is_hash_join_key_no(key) && 
-              (keyparts == 0 || keyuse->keypart != (keyuse-1)->keypart)) ||
+          if ((is_hash_join_key_no(key) && keyuse->keypart != NO_KEYPART) ||
               (!is_hash_join_key_no(key) && keyparts == keyuse->keypart &&
                !(found_part_ref_or_null & keyuse->optimize)))
           {
@@ -7357,6 +7388,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
     for (i=0 ; i < keyparts ; keyuse++,i++)
     {
       while (((~used_tables) & keyuse->used_tables) || 
+             keyuse->keypart == NO_KEYPART ||
 	     (keyuse->keypart != 
               (is_hash_join_key_no(key) ?
                  keyinfo->key_part[i].field->field_index : i)) || 
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 4333b825c2889dd6de0e706678518549bc27abeb..ffe3985c3c37b889a77085c65c0f0e0a663662b5 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -77,6 +77,8 @@ typedef struct keyuse_t {
   bool is_for_hash_join() { return is_hash_join_key_no(key); }
 } KEYUSE;
 
+#define NO_KEYPART ((uint)(-1))
+
 class store_key;
 
 const int NO_REF_PART= uint(-1);