diff --git a/src/js/_enqueues/lib/ajax-response.js b/src/js/_enqueues/lib/ajax-response.js
index 38816f3c38..659b91e023 100644
--- a/src/js/_enqueues/lib/ajax-response.js
+++ b/src/js/_enqueues/lib/ajax-response.js
@@ -18,7 +18,7 @@ window.wpAjax = jQuery.extend( {
 		return r;
 	},
 	parseAjaxResponse: function( x, r, e ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission.
-		var parsed = {}, re = jQuery('#' + r).empty(), err = '';
+		var parsed = {}, re = jQuery('#' + r).empty(), err = '', successmsg = '';
 
 		if ( x && typeof x === 'object' && x.getElementsByTagName('wp_ajax') ) {
 			parsed.responses = [];
@@ -27,6 +27,7 @@ window.wpAjax = jQuery.extend( {
 				var th = jQuery(this), child = jQuery(this.firstChild), response;
 				response = { action: th.attr('action'), what: child.get(0).nodeName, id: child.attr('id'), oldId: child.attr('old_id'), position: child.attr('position') };
 				response.data = jQuery( 'response_data', child ).text();
+				successmsg += response.data;
 				response.supplemental = {};
 				if ( !jQuery( 'supplemental', child ).children().each( function() {
 					response.supplemental[this.nodeName] = jQuery(this).text();
@@ -46,7 +47,14 @@ window.wpAjax = jQuery.extend( {
 				} ).length ) { response.errors = false; }
 				parsed.responses.push( response );
 			} );
-			if ( err.length ) { re.html( '<div class="error">' + err + '</div>' ); }
+			if ( err.length ) {
+				re.html( '<div class="error">' + err + '</div>' );
+				wp.a11y.speak( err );
+			} else {
+				re.html( '<div class="updated notice is-dismissible"><p>' + successmsg + '</p></div>');
+				jQuery(document).trigger( 'wp-updates-notice-added' );
+				wp.a11y.speak( successmsg );
+			}
 			return parsed;
 		}
 		if ( isNaN(x) ) { return !re.html('<div class="error"><p>' + x + '</p></div>'); }
diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php
index 1ba480f2f1..191e5b54dd 100644
--- a/src/wp-admin/includes/ajax-actions.php
+++ b/src/wp-admin/includes/ajax-actions.php
@@ -1102,9 +1102,19 @@ function wp_ajax_add_tag() {
 	$wp_list_table->single_row( $tag );
 	$parents = ob_get_clean();
 
+	require ABSPATH . 'wp-admin/includes/edit-tag-messages.php';
+
+	$message = '';
+	if ( isset( $messages[ $tax->name ][1] ) ) {
+		$message = $messages[ $tax->name ][1];
+	} elseif ( isset( $messages['_item'][1] ) ) {
+		$message = $messages['_item'][1];
+	}
+
 	$x->add(
 		array(
 			'what'         => 'taxonomy',
+			'data'         => $message,
 			'supplemental' => compact( 'parents', 'noparents' ),
 		)
 	);
diff --git a/tests/phpunit/tests/ajax/AddTag.php b/tests/phpunit/tests/ajax/AddTag.php
new file mode 100644
index 0000000000..48b5fc5f24
--- /dev/null
+++ b/tests/phpunit/tests/ajax/AddTag.php
@@ -0,0 +1,145 @@
+<?php
+
+/**
+ * Admin ajax functions to be tested.
+ */
+require_once ABSPATH . 'wp-admin/includes/ajax-actions.php';
+
+/**
+ * Class for testing ajax add tag functionality.
+ *
+ * @group ajax
+ */
+class Tests_Ajax_AddTag extends WP_Ajax_UnitTestCase {
+
+	/**
+	 * @dataProvider data_add_tag
+	 *
+	 * @ticket 42937
+	 *
+	 * @param array                 $post_data Data to populate $_POST.
+	 * @param string                $expected  Expected response.
+	 * @param array|string|callable $callback  Optional. Callback to register to 'term_updated_messages'
+	 *                                         filter. Default empty string (no callback).
+	 */
+	public function test_add_tag( array $post_data, $expected, $callback = '' ) {
+		$this->_setRole( 'administrator' );
+
+		$_POST                     = $post_data;
+		$_POST['_wpnonce_add-tag'] = wp_create_nonce( 'add-tag' );
+
+		if ( ! empty( $callback ) ) {
+			add_filter( 'term_updated_messages', $callback );
+		}
+
+		try {
+			$this->_handleAjax( 'add-tag' );
+		} catch ( WPAjaxDieContinueException $e ) {
+			unset( $e );
+		}
+
+		$this->assertSame( $expected, (string) $this->get_xml_response_taxonomy()->response_data );
+	}
+
+	/**
+	 * Data provider.
+	 *
+	 * @return array
+	 */
+	public function data_add_tag() {
+		return array(
+			'add a category'                        => array(
+				'post_data' => array(
+					'taxonomy'  => 'category',
+					'post_type' => 'post',
+					'screen'    => 'edit-category',
+					'action'    => 'add-tag',
+					'tag-name'  => 'blues',
+				),
+				'expected'  => 'Category added.',
+			),
+			'add a category with message filtering' => array(
+				'post_data' => array(
+					'taxonomy'  => 'category',
+					'post_type' => 'post',
+					'screen'    => 'edit-category',
+					'action'    => 'add-tag',
+					'tag-name'  => 'techno',
+				),
+				'expected'  => 'A new category added.',
+				'callback'  => static function( array $messages ) {
+					$messages['category'][1] = 'A new category added.';
+					return $messages;
+				},
+			),
+			'add a post_tag'                        => array(
+				'post_data' => array(
+					'taxonomy'  => 'post_tag',
+					'post_type' => 'post',
+					'screen'    => 'edit-post_tag',
+					'action'    => 'add-tag',
+					'tag-name'  => 'Louis Armstrong',
+				),
+				'expected'  => 'Tag added.',
+			),
+		);
+	}
+
+	/**
+	 * @ticket 42937
+	 */
+	public function test_adding_category_without_capability_should_error() {
+		$this->_setRole( 'subscriber' );
+
+		$_POST['taxonomy']         = 'category';
+		$_POST['post_type']        = 'post';
+		$_POST['screen']           = 'edit-category';
+		$_POST['action']           = 'add-tag';
+		$_POST['tag - name']       = 'disco';
+		$_POST['_wpnonce_add-tag'] = wp_create_nonce( 'add-tag' );
+
+		$this->expectException( 'WPAjaxDieStopException' );
+		$this->expectExceptionMessage( '-1' );
+		$this->_handleAjax( 'add-tag' );
+	}
+
+	/**
+	 * @ticket 42937
+	 */
+	public function test_adding_existing_category_should_error() {
+		$this->_setRole( 'administrator' );
+
+		wp_insert_term( 'testcat', 'category' );
+
+		$_POST = array(
+			'taxonomy'         => 'category',
+			'post_type'        => 'post',
+			'screen'           => 'edit-category',
+			'action'           => 'add-tag',
+			'tag-name'         => 'testcat',
+			'_wpnonce_add-tag' => wp_create_nonce( 'add-tag' ),
+		);
+
+		try {
+			$this->_handleAjax( 'add-tag' );
+		} catch ( WPAjaxDieContinueException $e ) {
+			unset( $e );
+		}
+
+		$expected = 'A term with the name provided already exists with this parent.';
+		$this->assertSame( $expected, (string) $this->get_xml_response_taxonomy()->wp_error );
+	}
+
+	/**
+	 * Helper method to get the taxonomy's response or error.
+	 *
+	 * @since 5.9.0
+	 *
+	 * @return SimpleXMLElement Response or error object.
+	 */
+	private function get_xml_response_taxonomy() {
+		$xml = simplexml_load_string( $this->_last_response, 'SimpleXMLElement', LIBXML_NOCDATA );
+
+		return $xml->response->taxonomy;
+	}
+}