diff --git a/modules/user/user.install b/modules/user/user.install
index d3d6f095a120c2df00dfaaa9c50bf6e56262baf2..d6357ed1294661510836dec5c9c42526d248f513 100644
--- a/modules/user/user.install
+++ b/modules/user/user.install
@@ -65,6 +65,13 @@ function user_schema() {
         'default' => '',
         'description' => 'A single permission granted to the role identified by rid.',
       ),
+      'module' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => "The module declaring the permission.",
+      ),
     ),
     'primary key' => array('rid', 'permission'),
     'indexes' => array(
@@ -490,3 +497,28 @@ function user_update_7005(&$sandbox) {
  * The next series of updates should start at 8000.
  */
 
+/**
+ * Add module data to {role_permission}.
+ */
+function user_update_7006(&$sandbox) {
+  $module_field = array(
+    'type' => 'varchar',
+    'length' => 255,
+    'not null' => TRUE,
+    'default' => '',
+    'description' => "The module declaring the permission.",
+  );
+  // Check that the field hasn't been updated in an aborted run of this
+  // update.
+  if (!db_column_exists('role_permission', 'module')) {
+    // Add a new field for the fid.
+    db_add_field('role_permission', 'module', $module_field);
+  }
+  $permissions = user_permissions_get_modules();
+  foreach ($permissions as $key => $value) {
+    db_update('role_permission')
+      ->fields(array('module' => $value))
+      ->condition('permission', $key)
+      ->execute();
+  }
+}
diff --git a/modules/user/user.module b/modules/user/user.module
index ed9aa6bf0cad688c4d1cbf0998e8c6865a16283f..01f2d3ff2217a5e585f28f3a3e3cec59b1bce4ce 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -2533,6 +2533,23 @@ function user_role_delete($role) {
   drupal_static_reset('user_role_permissions');
 }
 
+/**
+ * Determine the modules that permissions belong to.
+ *
+ * @return
+ *   An associative array in the format $permission => $module.
+ */
+function user_permission_get_modules() {
+  $permissions = array();
+  foreach (module_implements('permission') as $module) {
+    $perms = module_invoke($module, 'permission');
+    foreach ($perms as $key => $value) {
+      $permissions[$key] = $module;
+    }
+  }
+  return $permissions;
+}
+
 /**
  * Change permissions for a user role.
  *
@@ -2583,12 +2600,14 @@ function user_role_change_permissions($rid, array $permissions = array()) {
  * @see user_role_revoke_permissions()
  */
 function user_role_grant_permissions($rid, array $permissions = array()) {
+  $modules = user_permission_get_modules();
   // Grant new permissions for the role.
   foreach ($permissions as $name) {
     db_merge('role_permission')
       ->key(array(
         'rid' => $rid,
         'permission' => $name,
+        'module' => $modules[$name],
       ))
       ->execute();
   }
@@ -3332,17 +3351,9 @@ function user_modules_installed($modules) {
  * Implements hook_modules_uninstalled().
  */
 function user_modules_uninstalled($modules) {
-  $permissions = array();
-  foreach ($modules as $module) {
-    if (function_exists($module . '_permission')) {
-      $permissions = array_merge($permissions, array_keys(module_invoke($module, 'permission')));
-    }
-  }
-  if (!empty($permissions)) {
-    db_delete('role_permission')
-      ->condition('permission', $permissions, 'IN')
-      ->execute();
-  }
+   db_delete('role_permission')
+     ->condition('module', $modules, 'IN')
+     ->execute();
 }
 
 /**