Index: src/wp-includes/taxonomy.php
===================================================================
--- src/wp-includes/taxonomy.php	(revision 38469)
+++ src/wp-includes/taxonomy.php	(working copy)
@@ -61,6 +61,12 @@
 		'show_ui' => true,
 		'show_admin_column' => true,
 		'_builtin' => true,
+		'capabilities' => array(
+			'manage_terms' => 'manage_categories',
+			'edit_terms'   => 'edit_categories',
+			'delete_terms' => 'delete_categories',
+			'assign_terms' => 'assign_categories',
+		),
 	) );
 
 	register_taxonomy( 'post_tag', 'post', array(
@@ -71,6 +77,12 @@
 		'show_ui' => true,
 		'show_admin_column' => true,
 		'_builtin' => true,
+		'capabilities' => array(
+			'manage_terms' => 'manage_post_tags',
+			'edit_terms'   => 'edit_post_tags',
+			'delete_terms' => 'delete_post_tags',
+			'assign_terms' => 'assign_post_tags',
+		),
 	) );
 
 	register_taxonomy( 'nav_menu', 'nav_menu_item', array(
Index: src/wp-includes/link-template.php
===================================================================
--- src/wp-includes/link-template.php	(revision 38469)
+++ src/wp-includes/link-template.php	(working copy)
@@ -930,7 +930,7 @@
 	}
 
 	$tax = get_taxonomy( $term->taxonomy );
-	if ( ! $tax || ! current_user_can( $tax->cap->edit_terms ) ) {
+	if ( ! $tax || ! current_user_can( 'edit_term', $term->term_id ) ) {
 		return;
 	}
 
@@ -984,8 +984,9 @@
 		return;
 
 	$tax = get_taxonomy( $term->taxonomy );
-	if ( ! current_user_can( $tax->cap->edit_terms ) )
+	if ( ! current_user_can( 'edit_term', $term->term_id ) ) {
 		return;
+	}
 
 	if ( empty( $link ) )
 		$link = __('Edit This');
Index: src/wp-includes/class-wp-xmlrpc-server.php
===================================================================
--- src/wp-includes/class-wp-xmlrpc-server.php	(revision 38469)
+++ src/wp-includes/class-wp-xmlrpc-server.php	(working copy)
@@ -1882,8 +1882,9 @@
 
 		$taxonomy = get_taxonomy( $content_struct['taxonomy'] );
 
-		if ( ! current_user_can( $taxonomy->cap->manage_terms ) )
+		if ( ! current_user_can( $taxonomy->cap->edit_terms ) ) {
 			return new IXR_Error( 401, __( 'Sorry, you are not allowed to create terms in this taxonomy.' ) );
+		}
 
 		$taxonomy = (array) $taxonomy;
 
@@ -2065,8 +2066,9 @@
 
 		$taxonomy = get_taxonomy( $taxonomy );
 
-		if ( ! current_user_can( $taxonomy->cap->delete_terms ) )
-			return new IXR_Error( 401, __( 'Sorry, you are not allowed to delete terms in this taxonomy.' ) );
+		if ( ! current_user_can( 'delete_term', $term_id ) ) {
+			return new IXR_Error( 401, __( 'Sorry, you are not allowed to delete this term.' ) );
+		}
 
 		$term = get_term( $term_id, $taxonomy->name );
 
Index: src/wp-includes/capabilities.php
===================================================================
--- src/wp-includes/capabilities.php	(revision 38469)
+++ src/wp-includes/capabilities.php	(working copy)
@@ -402,6 +402,44 @@
 	case 'delete_site':
 		$caps[] = 'manage_options';
 		break;
+	case 'edit_term':
+	case 'delete_term':
+	case 'assign_term':
+		$term_id = $args[0];
+		$term = get_term( $term_id );
+		if ( ! $term || is_wp_error( $term ) ) {
+			$caps[] = 'do_not_allow';
+			break;
+		}
+
+		$tax = get_taxonomy( $term->taxonomy );
+		if ( ! $tax ) {
+			$caps[] = 'do_not_allow';
+			break;
+		}
+
+		if ( 'delete_term' === $cap && ( $term->term_id == get_option( 'default_' . $term->taxonomy ) ) ) {
+			$caps[] = 'do_not_allow';
+			break;
+		}
+
+		$taxo_cap = $cap . 's';
+
+		$caps = map_meta_cap( $tax->cap->$taxo_cap, $user_id, $term_id );
+
+		break;
+	case 'manage_categories':
+	case 'manage_post_tags':
+	case 'edit_categories':
+	case 'edit_post_tags':
+	case 'delete_categories':
+	case 'delete_post_tags':
+		$caps[] = 'manage_categories';
+		break;
+	case 'assign_categories':
+	case 'assign_post_tags':
+		$caps[] = 'edit_posts';
+		break;
 	default:
 		// Handle meta capabilities for custom post types.
 		global $post_type_meta_caps;
@@ -413,7 +451,7 @@
 		// If no meta caps match, return the original cap.
 		$caps[] = $cap;
 	}
-
+	
 	/**
 	 * Filters a user's capabilities depending on specific context and/or privilege.
 	 *
Index: src/wp-includes/admin-bar.php
===================================================================
--- src/wp-includes/admin-bar.php	(revision 38469)
+++ src/wp-includes/admin-bar.php	(working copy)
@@ -605,7 +605,7 @@
 			) );
 		} elseif ( ! empty( $current_object->taxonomy )
 			&& ( $tax = get_taxonomy( $current_object->taxonomy ) )
-			&& current_user_can( $tax->cap->edit_terms )
+			&& current_user_can( 'edit_term', $current_object->term_id )
 			&& $edit_term_link = get_edit_term_link( $current_object->term_id, $current_object->taxonomy ) )
 		{
 			$wp_admin_bar->add_menu( array(
Index: src/wp-admin/term.php
===================================================================
--- src/wp-admin/term.php	(revision 38469)
+++ src/wp-admin/term.php	(working copy)
@@ -31,11 +31,11 @@
 $title    = $tax->labels->edit_item;
 
 if ( ! in_array( $taxonomy, get_taxonomies( array( 'show_ui' => true ) ) ) ||
-     ! current_user_can( $tax->cap->manage_terms )
+     ! current_user_can( 'edit_term', $tag->term_id )
 ) {
 	wp_die(
 		'<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
-		'<p>' . __( 'Sorry, you are not allowed to manage this item.' ) . '</p>',
+		'<p>' . __( 'Sorry, you are not allowed to edit this item.' ) . '</p>',
 		403
 	);
 }
Index: src/wp-admin/includes/class-wp-terms-list-table.php
===================================================================
--- src/wp-admin/includes/class-wp-terms-list-table.php	(revision 38469)
+++ src/wp-admin/includes/class-wp-terms-list-table.php	(working copy)
@@ -332,11 +332,10 @@
 	 * @return string
 	 */
 	public function column_cb( $tag ) {
-		$default_term = get_option( 'default_' . $this->screen->taxonomy );
-
-		if ( current_user_can( get_taxonomy( $this->screen->taxonomy )->cap->delete_terms ) && $tag->term_id != $default_term )
+		if ( current_user_can( 'delete_term', $tag->term_id ) ) {
 			return '<label class="screen-reader-text" for="cb-select-' . $tag->term_id . '">' . sprintf( __( 'Select %s' ), $tag->name ) . '</label>'
 				. '<input type="checkbox" name="delete_tags[]" value="' . $tag->term_id . '" id="cb-select-' . $tag->term_id . '" />';
+		}
 
 		return '&nbsp;';
 	}
@@ -411,9 +410,9 @@
 	 * @since 4.3.0
 	 * @access protected
 	 *
-	 * @param object $tag         Tag being acted upon.
-	 * @param string $column_name Current column name.
-	 * @param string $primary     Primary column name.
+	 * @param WP_Term $tag         Tag being acted upon.
+	 * @param string  $column_name Current column name.
+	 * @param string  $primary     Primary column name.
 	 * @return string Row actions output for terms.
 	 */
 	protected function handle_row_actions( $tag, $column_name, $primary ) {
@@ -423,8 +422,6 @@
 
 		$taxonomy = $this->screen->taxonomy;
 		$tax = get_taxonomy( $taxonomy );
-		$default_term = get_option( 'default_' . $taxonomy );
-
 		$uri = wp_doing_ajax() ? wp_get_referer() : $_SERVER['REQUEST_URI'];
 
 		$edit_link = add_query_arg(
@@ -434,7 +431,7 @@
 		);
 
 		$actions = array();
-		if ( current_user_can( $tax->cap->edit_terms ) ) {
+		if ( current_user_can( 'edit_term', $tag->term_id ) ) {
 			$actions['edit'] = sprintf(
 				'<a href="%s" aria-label="%s">%s</a>',
 				esc_url( $edit_link ),
@@ -449,7 +446,7 @@
 				__( 'Quick&nbsp;Edit' )
 			);
 		}
-		if ( current_user_can( $tax->cap->delete_terms ) && $tag->term_id != $default_term ) {
+		if ( current_user_can( 'delete_term', $tag->term_id ) ) {
 			$actions['delete'] = sprintf(
 				'<a href="%s" class="delete-tag aria-button-if-js" aria-label="%s">%s</a>',
 				wp_nonce_url( "edit-tags.php?action=delete&amp;taxonomy=$taxonomy&amp;tag_ID=$tag->term_id", 'delete-tag_' . $tag->term_id ),
Index: src/wp-admin/includes/ajax-actions.php
===================================================================
--- src/wp-admin/includes/ajax-actions.php	(revision 38469)
+++ src/wp-admin/includes/ajax-actions.php	(working copy)
@@ -597,8 +597,9 @@
 	$taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
 	$tax = get_taxonomy($taxonomy);
 
-	if ( !current_user_can( $tax->cap->delete_terms ) )
+	if ( ! current_user_can( 'delete_term', $tag_id ) ) {
 		wp_die( -1 );
+	}
 
 	$tag = get_term( $tag_id, $taxonomy );
 	if ( !$tag || is_wp_error( $tag ) )
@@ -786,7 +787,7 @@
 }
 
 /**
- * Ajax handler for deleting a link category.
+ * Ajax handler for inserting a link category.
  *
  * @since 3.1.0
  *
@@ -796,8 +797,10 @@
 	if ( empty( $action ) )
 		$action = 'add-link-category';
 	check_ajax_referer( $action );
-	if ( !current_user_can( 'manage_categories' ) )
+	$tax = get_taxonomy( 'link_category' );
+	if ( ! current_user_can( $tax->cap->manage_terms ) ) {
 		wp_die( -1 );
+	}
 	$names = explode(',', wp_unslash( $_POST['newcat'] ) );
 	$x = new WP_Ajax_Response();
 	foreach ( $names as $cat_name ) {
@@ -1702,13 +1705,15 @@
 	if ( ! $tax )
 		wp_die( 0 );
 
-	if ( ! current_user_can( $tax->cap->edit_terms ) )
+	if ( ! isset( $_POST['tax_ID'] ) || ! ( $id = (int) $_POST['tax_ID'] ) ) {
 		wp_die( -1 );
+	}
 
-	$wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
-
-	if ( ! isset($_POST['tax_ID']) || ! ( $id = (int) $_POST['tax_ID'] ) )
+	if ( ! current_user_can( 'edit_term', $id ) ) {
 		wp_die( -1 );
+	}
+
+	$wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
 
 	$tag = get_term( $id, $taxonomy );
 	$_POST['description'] = $tag->description;
Index: src/wp-admin/edit-tags.php
===================================================================
--- src/wp-admin/edit-tags.php	(revision 38469)
+++ src/wp-admin/edit-tags.php	(working copy)
@@ -108,7 +108,7 @@
 	$tag_ID = (int) $_REQUEST['tag_ID'];
 	check_admin_referer( 'delete-tag_' . $tag_ID );
 
-	if ( ! current_user_can( $tax->cap->delete_terms ) ) {
+	if ( ! current_user_can( 'delete_term', $tag_ID ) ) {
 		wp_die(
 			'<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
 			'<p>' . __( 'Sorry, you are not allowed to delete this item.' ) . '</p>',
@@ -168,7 +168,7 @@
 	$tag_ID = (int) $_POST['tag_ID'];
 	check_admin_referer( 'update-tag_' . $tag_ID );
 
-	if ( ! current_user_can( $tax->cap->edit_terms ) ) {
+	if ( ! current_user_can( 'edit_term', $tag_ID ) ) {
 		wp_die(
 			'<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
 			'<p>' . __( 'Sorry, you are not allowed to edit this item.' ) . '</p>',
@@ -294,14 +294,6 @@
 
 require_once( ABSPATH . 'wp-admin/admin-header.php' );
 
-if ( ! current_user_can( $tax->cap->edit_terms ) ) {
-	wp_die(
-		'<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
-		'<p>' . __( 'Sorry, you are not allowed to edit this item.' ) . '</p>',
-		403
-	);
-}
-
 /** Also used by the Edit Tag  form */
 require_once( ABSPATH . 'wp-admin/includes/edit-tag-messages.php' );
 
