diff --git a/mysql-test/suite/roles/drop_routines.result b/mysql-test/suite/roles/drop_routines.result
new file mode 100644
index 00000000000..bbb6cc6ca39
--- /dev/null
+++ b/mysql-test/suite/roles/drop_routines.result
@@ -0,0 +1,104 @@
+create role r1;
+create role r2;
+create role r3;
+create role r4;
+create user u1;
+grant r2 to r1;
+grant r3 to r2;
+grant r4 to r3;
+grant r1 to u1;
+grant r4 to r1;
+show grants for u1;
+Grants for u1@%
+GRANT USAGE ON *.* TO 'u1'@'%'
+GRANT r1 TO 'u1'@'%'
+show grants for r1;
+Grants for r1
+GRANT USAGE ON *.* TO 'r1'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r2 TO 'r1'
+GRANT r3 TO 'r2'
+GRANT r4 TO 'r1'
+GRANT r4 TO 'r3'
+grant SELECT on *.* to u1;
+grant INSERT on mysql.* to r1;
+grant DELETE on mysql.roles_mapping to r2;
+grant UPDATE on mysql.user to r3;
+create function mysql.test_func (s CHAR(20))
+returns CHAR(50) DETERMINISTIC
+return concat('Test string: ',s);
+create procedure mysql.test_proc (OUT param1 INT)
+begin
+select COUNT(*) into param1 from mysql.roles_mapping;
+end|
+grant execute on function mysql.test_func to r2;
+grant execute on procedure mysql.test_proc to r3;
+grant execute on mysql.* to r4;
+show grants for r1;
+Grants for r1
+GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2'
+GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2'
+GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3'
+GRANT EXECUTE ON `mysql`.* TO 'r4'
+GRANT INSERT ON `mysql`.* TO 'r1'
+GRANT UPDATE ON `mysql`.`user` TO 'r3'
+GRANT USAGE ON *.* TO 'r1'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r2 TO 'r1'
+GRANT r3 TO 'r2'
+GRANT r4 TO 'r1'
+GRANT r4 TO 'r3'
+show grants for r2;
+Grants for r2
+GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2'
+GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2'
+GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3'
+GRANT EXECUTE ON `mysql`.* TO 'r4'
+GRANT UPDATE ON `mysql`.`user` TO 'r3'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r3 TO 'r2'
+GRANT r4 TO 'r3'
+show grants for r3;
+Grants for r3
+GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3'
+GRANT EXECUTE ON `mysql`.* TO 'r4'
+GRANT UPDATE ON `mysql`.`user` TO 'r3'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r4 TO 'r3'
+show grants for r4;
+Grants for r4
+GRANT EXECUTE ON `mysql`.* TO 'r4'
+GRANT USAGE ON *.* TO 'r4'
+drop function mysql.test_func;
+Warnings:
+Warning	1403	There is no such grant defined for user 'r1' on host '' on routine 'test_func'
+Warning	1403	There is no such grant defined for user 'r1' on host '' on routine 'test_func'
+drop procedure mysql.test_proc;
+Warnings:
+Warning	1403	There is no such grant defined for user 'r2' on host '' on routine 'test_proc'
+Warning	1403	There is no such grant defined for user 'r1' on host '' on routine 'test_proc'
+Warning	1403	There is no such grant defined for user 'r2' on host '' on routine 'test_proc'
+Warning	1403	There is no such grant defined for user 'r1' on host '' on routine 'test_proc'
+show grants for r1;
+Grants for r1
+GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2'
+GRANT EXECUTE ON `mysql`.* TO 'r4'
+GRANT INSERT ON `mysql`.* TO 'r1'
+GRANT UPDATE ON `mysql`.`user` TO 'r3'
+GRANT USAGE ON *.* TO 'r1'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r2 TO 'r1'
+GRANT r3 TO 'r2'
+GRANT r4 TO 'r1'
+GRANT r4 TO 'r3'
+drop role r1, r2, r3, r4;
+drop user u1;
diff --git a/mysql-test/suite/roles/drop_routines.test b/mysql-test/suite/roles/drop_routines.test
new file mode 100644
index 00000000000..78f2039f55a
--- /dev/null
+++ b/mysql-test/suite/roles/drop_routines.test
@@ -0,0 +1,61 @@
+source include/not_embedded.inc;
+
+create role r1;
+create role r2;
+create role r3;
+create role r4;
+create user u1;
+
+#CREATE A CHAIN OF ROLES
+grant r2 to r1;
+grant r3 to r2;
+grant r4 to r3;
+grant r1 to u1;
+grant r4 to r1;
+
+--sorted_result
+show grants for u1;
+--sorted_result
+show grants for r1;
+
+grant SELECT on *.* to u1;
+grant INSERT on mysql.* to r1;
+grant DELETE on mysql.roles_mapping to r2;
+grant UPDATE on mysql.user to r3;
+
+create function mysql.test_func (s CHAR(20))
+returns CHAR(50) DETERMINISTIC
+return concat('Test string: ',s);
+
+
+delimiter |;
+create procedure mysql.test_proc (OUT param1 INT)
+begin
+  select COUNT(*) into param1 from mysql.roles_mapping;
+end|
+delimiter ;|
+
+grant execute on function mysql.test_func to r2;
+grant execute on procedure mysql.test_proc to r3;
+grant execute on mysql.* to r4;
+
+--sorted_result
+show grants for r1;
+--sorted_result
+show grants for r2;
+--sorted_result
+show grants for r3;
+--sorted_result
+show grants for r4;
+
+drop function mysql.test_func;
+drop procedure mysql.test_proc;
+
+# HERE there are func_priv_hash and proc_priv hash entries inherited from other roles that are not
+# deleted. These remain and could affect privilege checks
+
+--sorted_result
+show grants for r1;
+
+drop role r1, r2, r3, r4;
+drop user u1;
diff --git a/mysql-test/suite/roles/revoke_all.result b/mysql-test/suite/roles/revoke_all.result
new file mode 100644
index 00000000000..7e72b5bc766
--- /dev/null
+++ b/mysql-test/suite/roles/revoke_all.result
@@ -0,0 +1,183 @@
+create role r1;
+create role r2;
+create role r3;
+create role r4;
+create user u1;
+grant r2 to r1;
+grant r3 to r2;
+grant r4 to r3;
+grant r1 to u1;
+grant r4 to r1;
+show grants for u1;
+Grants for u1@%
+GRANT USAGE ON *.* TO 'u1'@'%'
+GRANT r1 TO 'u1'@'%'
+show grants for r1;
+Grants for r1
+GRANT USAGE ON *.* TO 'r1'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r2 TO 'r1'
+GRANT r3 TO 'r2'
+GRANT r4 TO 'r1'
+GRANT r4 TO 'r3'
+grant SELECT on *.* to u1;
+grant INSERT on mysql.* to r1;
+grant DELETE on mysql.roles_mapping to r2;
+grant UPDATE on mysql.user to r3;
+create function mysql.test_func (s CHAR(20))
+returns CHAR(50) DETERMINISTIC
+return concat('Test string: ',s);
+create procedure mysql.test_proc (OUT param1 INT)
+begin
+select COUNT(*) into param1 from mysql.roles_mapping;
+end|
+grant execute on function mysql.test_func to r2;
+grant execute on procedure mysql.test_proc to r3;
+grant execute on mysql.* to r4;
+show grants for r1;
+Grants for r1
+GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2'
+GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2'
+GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3'
+GRANT EXECUTE ON `mysql`.* TO 'r4'
+GRANT INSERT ON `mysql`.* TO 'r1'
+GRANT UPDATE ON `mysql`.`user` TO 'r3'
+GRANT USAGE ON *.* TO 'r1'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r2 TO 'r1'
+GRANT r3 TO 'r2'
+GRANT r4 TO 'r1'
+GRANT r4 TO 'r3'
+show grants for r2;
+Grants for r2
+GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2'
+GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2'
+GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3'
+GRANT EXECUTE ON `mysql`.* TO 'r4'
+GRANT UPDATE ON `mysql`.`user` TO 'r3'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r3 TO 'r2'
+GRANT r4 TO 'r3'
+show grants for r3;
+Grants for r3
+GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3'
+GRANT EXECUTE ON `mysql`.* TO 'r4'
+GRANT UPDATE ON `mysql`.`user` TO 'r3'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r4 TO 'r3'
+show grants for r4;
+Grants for r4
+GRANT EXECUTE ON `mysql`.* TO 'r4'
+GRANT USAGE ON *.* TO 'r4'
+revoke all privileges, grant option from r4;
+show grants for r1;
+Grants for r1
+GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2'
+GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2'
+GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3'
+GRANT INSERT ON `mysql`.* TO 'r1'
+GRANT UPDATE ON `mysql`.`user` TO 'r3'
+GRANT USAGE ON *.* TO 'r1'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r2 TO 'r1'
+GRANT r3 TO 'r2'
+GRANT r4 TO 'r1'
+GRANT r4 TO 'r3'
+show grants for r2;
+Grants for r2
+GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2'
+GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2'
+GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3'
+GRANT UPDATE ON `mysql`.`user` TO 'r3'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r3 TO 'r2'
+GRANT r4 TO 'r3'
+show grants for r3;
+Grants for r3
+GRANT EXECUTE ON PROCEDURE `mysql`.`test_proc` TO 'r3'
+GRANT UPDATE ON `mysql`.`user` TO 'r3'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r4 TO 'r3'
+show grants for r4;
+Grants for r4
+GRANT USAGE ON *.* TO 'r4'
+revoke all privileges, grant option from r3;
+show grants for r1;
+Grants for r1
+GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2'
+GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2'
+GRANT INSERT ON `mysql`.* TO 'r1'
+GRANT USAGE ON *.* TO 'r1'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r2 TO 'r1'
+GRANT r3 TO 'r2'
+GRANT r4 TO 'r1'
+show grants for r2;
+Grants for r2
+GRANT DELETE ON `mysql`.`roles_mapping` TO 'r2'
+GRANT EXECUTE ON FUNCTION `mysql`.`test_func` TO 'r2'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r3'
+GRANT r3 TO 'r2'
+show grants for r3;
+Grants for r3
+GRANT USAGE ON *.* TO 'r3'
+show grants for r4;
+Grants for r4
+GRANT USAGE ON *.* TO 'r4'
+revoke all privileges, grant option from r2;
+show grants for r1;
+Grants for r1
+GRANT INSERT ON `mysql`.* TO 'r1'
+GRANT USAGE ON *.* TO 'r1'
+GRANT USAGE ON *.* TO 'r2'
+GRANT USAGE ON *.* TO 'r4'
+GRANT r2 TO 'r1'
+GRANT r4 TO 'r1'
+show grants for r2;
+Grants for r2
+GRANT USAGE ON *.* TO 'r2'
+show grants for r3;
+Grants for r3
+GRANT USAGE ON *.* TO 'r3'
+show grants for r4;
+Grants for r4
+GRANT USAGE ON *.* TO 'r4'
+revoke all privileges, grant option from r1;
+show grants for r1;
+Grants for r1
+GRANT USAGE ON *.* TO 'r1'
+show grants for r2;
+Grants for r2
+GRANT USAGE ON *.* TO 'r2'
+show grants for r3;
+Grants for r3
+GRANT USAGE ON *.* TO 'r3'
+show grants for r4;
+Grants for r4
+GRANT USAGE ON *.* TO 'r4'
+revoke all privileges, grant option from u1;
+show grants for u1;
+Grants for u1@%
+GRANT USAGE ON *.* TO 'u1'@'%'
+drop function mysql.test_func;
+drop procedure mysql.test_proc;
+show grants for r1;
+Grants for r1
+GRANT USAGE ON *.* TO 'r1'
+drop role r1, r2, r3, r4;
+drop user u1;
diff --git a/mysql-test/suite/roles/revoke_all.test b/mysql-test/suite/roles/revoke_all.test
new file mode 100644
index 00000000000..a3dee981c40
--- /dev/null
+++ b/mysql-test/suite/roles/revoke_all.test
@@ -0,0 +1,103 @@
+source include/not_embedded.inc;
+
+create role r1;
+create role r2;
+create role r3;
+create role r4;
+create user u1;
+
+#CREATE A CHAIN OF ROLES
+grant r2 to r1;
+grant r3 to r2;
+grant r4 to r3;
+grant r1 to u1;
+grant r4 to r1;
+
+--sorted_result
+show grants for u1;
+--sorted_result
+show grants for r1;
+
+grant SELECT on *.* to u1;
+grant INSERT on mysql.* to r1;
+grant DELETE on mysql.roles_mapping to r2;
+grant UPDATE on mysql.user to r3;
+
+create function mysql.test_func (s CHAR(20))
+returns CHAR(50) DETERMINISTIC
+return concat('Test string: ',s);
+
+
+delimiter |;
+create procedure mysql.test_proc (OUT param1 INT)
+begin
+  select COUNT(*) into param1 from mysql.roles_mapping;
+end|
+delimiter ;|
+
+grant execute on function mysql.test_func to r2;
+grant execute on procedure mysql.test_proc to r3;
+grant execute on mysql.* to r4;
+
+--sorted_result
+show grants for r1;
+--sorted_result
+show grants for r2;
+--sorted_result
+show grants for r3;
+--sorted_result
+show grants for r4;
+
+revoke all privileges, grant option from r4;
+
+--sorted_result
+show grants for r1;
+--sorted_result
+show grants for r2;
+--sorted_result
+show grants for r3;
+--sorted_result
+show grants for r4;
+
+revoke all privileges, grant option from r3;
+--sorted_result
+show grants for r1;
+--sorted_result
+show grants for r2;
+--sorted_result
+show grants for r3;
+--sorted_result
+show grants for r4;
+
+revoke all privileges, grant option from r2;
+--sorted_result
+show grants for r1;
+--sorted_result
+show grants for r2;
+--sorted_result
+show grants for r3;
+--sorted_result
+show grants for r4;
+
+revoke all privileges, grant option from r1;
+--sorted_result
+show grants for r1;
+--sorted_result
+show grants for r2;
+--sorted_result
+show grants for r3;
+--sorted_result
+show grants for r4;
+
+revoke all privileges, grant option from u1;
+
+show grants for u1;
+
+drop function mysql.test_func;
+drop procedure mysql.test_proc;
+
+--sorted_result
+show grants for r1;
+
+drop role r1, r2, r3, r4;
+drop user u1;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index f1344ebaf96..94c880a6848 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2385,7 +2385,7 @@ static bool add_role_user_mapping(const char *uname, const char *hname,
 /*
   This helper function is used to removes roles and grantees
   from the corresponding cross-reference arrays. see remove_role_user_mapping().
-  as such, it asserts that a element to delete is present in the array,
+  as such, it asserts that an element to delete is present in the array,
   and is present only once.
 */
 static void remove_ptr_from_dynarray(DYNAMIC_ARRAY *array, void *ptr)
@@ -4371,6 +4371,9 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
       The following should never happen as we first check the in memory
       grant tables for the user.  There is however always a small change that
       the user has modified the grant tables directly.
+
+      Also, there is also a second posibility that this routine entry
+      is created for a role by being inherited from a granted role.
     */
     if (revoke_grant)
     { // no row, no revoke
@@ -9323,7 +9326,10 @@ bool mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
       result= -1;
       continue;
     }
-    if (!find_user_exact(lex_user->host.str, lex_user->user.str))
+
+    /* This is not a role and the user could not be found */
+    if (!lex_user->is_role() &&
+        !find_user_exact(lex_user->host.str, lex_user->user.str))
     {
       result= -1;
       continue;
@@ -9429,6 +9435,10 @@ bool mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
 	if (!strcmp(lex_user->user.str,user) &&
             !strcmp(lex_user->host.str, host))
 	{
+          /* only inherited rights, nothing to do here */
+          if (!grant_proc->init_privs)
+            continue;
+
 	  if (replace_routine_table(thd,grant_proc,tables[4].table,*lex_user,
 				  grant_proc->db,
 				  grant_proc->tname,
@@ -9443,6 +9453,59 @@ bool mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
 	counter++;
       }
     } while (revoked);
+
+    ACL_USER_BASE *user_or_role;
+    /* remove role grants */
+    if (lex_user->is_role())
+    {
+      /* this can not fail due to get_current_user already having searched for it */
+      user_or_role= find_acl_role(lex_user->user.str);
+    }
+    else
+    {
+      user_or_role= find_user_exact(lex_user->host.str, lex_user->user.str);
+    }
+    /*
+      Find every role grant pair matching the role_grants array and remove it,
+      both from the acl_roles_mappings and the roles_mapping table
+    */
+    for (counter= 0; counter < user_or_role->role_grants.elements; counter++)
+    {
+      ACL_ROLE *role_grant= *dynamic_element(&user_or_role->role_grants,
+                                             counter, ACL_ROLE**);
+      ROLE_GRANT_PAIR *pair = find_role_grant_pair(&lex_user->user,
+                                                   &lex_user->host,
+                                                   &role_grant->user);
+      if (replace_roles_mapping_table(tables[6].table,
+                                      &lex_user->user,
+                                      &lex_user->host,
+                                      &role_grant->user, false, pair, true))
+      {
+        result= -1; //Something went wrong
+      }
+      /*
+        Delete from the parent_grantee array of the roles granted,
+        the entry pointing to this user_or_role
+      */
+      remove_ptr_from_dynarray(&role_grant->parent_grantee, user_or_role);
+    }
+    /* TODO
+       How to handle an error in the replace_roles_mapping_table, in
+       regards to the privileges held in memory
+    */
+
+    /* Finally, clear the role_grants array */
+    if (counter == user_or_role->role_grants.elements)
+    {
+      reset_dynamic(&user_or_role->role_grants);
+    }
+    /*
+      If we are revoking from a role, we need to update all the parent grantees
+    */
+    if (lex_user->is_role())
+    {
+      propagate_role_grants((ACL_ROLE *)user_or_role, PRIVS_TO_MERGE::ALL, 0, 0);
+    }
   }
 
   mysql_mutex_unlock(&acl_cache->lock);