diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php
index 90a9dd1..034ec2f 100644
--- a/src/wp-admin/includes/ajax-actions.php
+++ b/src/wp-admin/includes/ajax-actions.php
@@ -3643,7 +3643,7 @@ function wp_ajax_install_plugin() {
 	// If install request is coming from import page, do not return network activation link.
 	$plugins_url = ( 'import' === $pagenow ) ? admin_url( 'plugins.php' ) : network_admin_url( 'plugins.php' );
 
-	if ( current_user_can( 'activate_plugins' ) && is_plugin_inactive( $install_status['file'] ) ) {
+	if ( current_user_can( 'activate_plugin', $install_status['file'] ) && is_plugin_inactive( $install_status['file'] ) ) {
 		$status['activateUrl'] = add_query_arg( array(
 			'_wpnonce' => wp_create_nonce( 'activate-plugin_' . $install_status['file'] ),
 			'action'   => 'activate',
diff --git a/src/wp-admin/includes/class-plugin-installer-skin.php b/src/wp-admin/includes/class-plugin-installer-skin.php
index 6c55455..247387e 100644
--- a/src/wp-admin/includes/class-plugin-installer-skin.php
+++ b/src/wp-admin/includes/class-plugin-installer-skin.php
@@ -73,7 +73,7 @@ class Plugin_Installer_Skin extends WP_Upgrader_Skin {
 
 		if ( ! $this->result || is_wp_error($this->result) ) {
 			unset( $install_actions['activate_plugin'], $install_actions['network_activate'] );
-		} elseif ( ! current_user_can( 'activate_plugins' ) ) {
+		} elseif ( ! current_user_can( 'activate_plugin', $plugin_file ) ) {
 			unset( $install_actions['activate_plugin'] );
 		}
 
diff --git a/src/wp-admin/includes/class-plugin-upgrader-skin.php b/src/wp-admin/includes/class-plugin-upgrader-skin.php
index 1c4da87..b685bca 100644
--- a/src/wp-admin/includes/class-plugin-upgrader-skin.php
+++ b/src/wp-admin/includes/class-plugin-upgrader-skin.php
@@ -52,7 +52,7 @@ class Plugin_Upgrader_Skin extends WP_Upgrader_Skin {
 			'activate_plugin' => '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $this->plugin ), 'activate-plugin_' . $this->plugin) . '" target="_parent">' . __( 'Activate Plugin' ) . '</a>',
 			'plugins_page' => '<a href="' . self_admin_url( 'plugins.php' ) . '" target="_parent">' . __( 'Return to Plugins page' ) . '</a>'
 		);
-		if ( $this->plugin_active || ! $this->result || is_wp_error( $this->result ) || ! current_user_can( 'activate_plugins' ) )
+		if ( $this->plugin_active || ! $this->result || is_wp_error( $this->result ) || ! current_user_can( 'activate_plugin', $this->plugin ) )
 			unset( $update_actions['activate_plugin'] );
 
 		/**
diff --git a/src/wp-admin/includes/class-wp-plugin-install-list-table.php b/src/wp-admin/includes/class-wp-plugin-install-list-table.php
index cd71836..e67ca54 100644
--- a/src/wp-admin/includes/class-wp-plugin-install-list-table.php
+++ b/src/wp-admin/includes/class-wp-plugin-install-list-table.php
@@ -470,7 +470,7 @@ class WP_Plugin_Install_List_Table extends WP_List_Table {
 					case 'newer_installed':
 						if ( is_plugin_active( $status['file'] ) ) {
 							$action_links[] = '<button type="button" class="button button-disabled" disabled="disabled">' . _x( 'Active', 'plugin' ) . '</button>';
-						} elseif ( current_user_can( 'activate_plugins' ) ) {
+						} elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
 							$button_text  = __( 'Activate' );
 							/* translators: %s: Plugin name */
 							$button_label = _x( 'Activate %s', 'plugin' );
diff --git a/src/wp-admin/includes/class-wp-plugins-list-table.php b/src/wp-admin/includes/class-wp-plugins-list-table.php
index 136fbd4..4128edf 100644
--- a/src/wp-admin/includes/class-wp-plugins-list-table.php
+++ b/src/wp-admin/includes/class-wp-plugins-list-table.php
@@ -623,11 +623,15 @@ class WP_Plugins_List_Table extends WP_List_Table {
 						'network_only' => __( 'Network Only' ),
 					);
 				} elseif ( $is_active ) {
-					/* translators: %s: plugin name */
-					$actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Deactivate' ) . '</a>';
+					if ( current_user_can( 'deactivate_plugin', $plugin_file ) ) {
+						/* translators: %s: plugin name */
+						$actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Deactivate' ) . '</a>';
+					}
 				} else {
-					/* translators: %s: plugin name */
-					$actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Activate' ) . '</a>';
+					if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
+						/* translators: %s: plugin name */
+						$actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Activate' ) . '</a>';
+					}
 
 					if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
 						/* translators: %s: plugin name */
diff --git a/src/wp-admin/plugins.php b/src/wp-admin/plugins.php
index 3d7ff01..e19f584 100644
--- a/src/wp-admin/plugins.php
+++ b/src/wp-admin/plugins.php
@@ -29,8 +29,9 @@ if ( $action ) {
 
 	switch ( $action ) {
 		case 'activate':
-			if ( ! current_user_can('activate_plugins') )
-				wp_die(__('Sorry, you are not allowed to activate plugins for this site.'));
+			if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
+				wp_die( __( 'Sorry, you are not allowed to activate this plugin.' ) );
+			}
 
 			if ( is_multisite() && ! is_network_admin() && is_network_only_plugin( $plugin ) ) {
 				wp_redirect( self_admin_url("plugins.php?plugin_status=$status&paged=$page&s=$s") );
@@ -88,6 +89,10 @@ if ( $action ) {
 					if ( is_plugin_active( $plugin ) || ( is_multisite() && is_network_only_plugin( $plugin ) ) ) {
 						unset( $plugins[ $i ] );
 					}
+					// Only activate plugins which the user can activate.
+					if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
+						unset( $plugins[ $i ] );
+					}
 				}
 			}
 
@@ -146,8 +151,9 @@ if ( $action ) {
 			exit;
 
 		case 'error_scrape':
-			if ( ! current_user_can('activate_plugins') )
-				wp_die(__('Sorry, you are not allowed to activate plugins for this site.'));
+			if ( ! current_user_can( 'activate_plugin', $plugin ) ) {
+				wp_die( __( 'Sorry, you are not allowed to activate this plugin.' ) );
+			}
 
 			check_admin_referer('plugin-activation-error_' . $plugin);
 
@@ -167,8 +173,9 @@ if ( $action ) {
 			exit;
 
 		case 'deactivate':
-			if ( ! current_user_can('activate_plugins') )
-				wp_die(__('Sorry, you are not allowed to deactivate plugins for this site.'));
+			if ( ! current_user_can( 'deactivate_plugin', $plugin ) ) {
+				wp_die( __( 'Sorry, you are not allowed to deactivate this plugin.' ) );
+			}
 
 			check_admin_referer('deactivate-plugin_' . $plugin);
 
@@ -192,8 +199,9 @@ if ( $action ) {
 			exit;
 
 		case 'deactivate-selected':
-			if ( ! current_user_can('activate_plugins') )
+			if ( ! current_user_can( 'deactivate_plugins' ) ) {
 				wp_die(__('Sorry, you are not allowed to deactivate plugins for this site.'));
+			}
 
 			check_admin_referer('bulk-plugins');
 
@@ -204,6 +212,14 @@ if ( $action ) {
 			} else {
 				$plugins = array_filter( $plugins, 'is_plugin_active' );
 				$plugins = array_diff( $plugins, array_filter( $plugins, 'is_plugin_active_for_network' ) );
+
+				foreach ( $plugins as $i => $plugin ) {
+					// Only deactivate plugins which the user can deactivate.
+					if ( ! current_user_can( 'deactivate_plugin', $plugin ) ) {
+						unset( $plugins[ $i ] );
+					}
+				}
+
 			}
 			if ( empty($plugins) ) {
 				wp_redirect( self_admin_url("plugins.php?plugin_status=$status&paged=$page&s=$s") );
diff --git a/src/wp-includes/capabilities.php b/src/wp-includes/capabilities.php
index abd8725..387f029 100644
--- a/src/wp-includes/capabilities.php
+++ b/src/wp-includes/capabilities.php
@@ -393,7 +393,10 @@ function map_meta_cap( $cap, $user_id ) {
 		}
 		break;
 	case 'activate_plugins':
-		$caps[] = $cap;
+	case 'deactivate_plugins':
+	case 'activate_plugin':
+	case 'deactivate_plugin':
+		$caps[] = 'activate_plugins';
 		if ( is_multisite() ) {
 			// update_, install_, and delete_ are handled above with is_super_admin().
 			$menu_perms = get_site_option( 'menu_items', array() );
diff --git a/tests/phpunit/tests/user/capabilities.php b/tests/phpunit/tests/user/capabilities.php
index a479011..b2eb3f5 100644
--- a/tests/phpunit/tests/user/capabilities.php
+++ b/tests/phpunit/tests/user/capabilities.php
@@ -233,6 +233,7 @@ class Tests_User_Capabilities extends WP_UnitTestCase {
 			'upload_themes'          => array( 'administrator' ),
 			'customize'              => array( 'administrator' ),
 			'add_users'              => array( 'administrator' ),
+			'deactivate_plugins'     => array( 'administrator' ),
 
 			'edit_categories'        => array( 'administrator', 'editor' ),
 			'delete_categories'      => array( 'administrator', 'editor' ),
@@ -261,6 +262,7 @@ class Tests_User_Capabilities extends WP_UnitTestCase {
 			'upload_themes'          => array(),
 			'edit_css'               => array(),
 			'upgrade_network'        => array(),
+			'deactivate_plugins'     => array(),
 
 			'customize'              => array( 'administrator' ),
 			'delete_site'            => array( 'administrator' ),
@@ -421,6 +423,8 @@ class Tests_User_Capabilities extends WP_UnitTestCase {
 			$expected['create_users'],
 			$expected['manage_links'],
 			// Singular object meta capabilities (where an object ID is passed) are not tested:
+			$expected['activate_plugin'],
+			$expected['deactivate_plugin'],
 			$expected['remove_user'],
 			$expected['promote_user'],
 			$expected['edit_user'],
