diff --git src/wp-includes/class-wp-meta-query.php src/wp-includes/class-wp-meta-query.php
index d9234c2..b48c58f 100644
--- src/wp-includes/class-wp-meta-query.php
+++ src/wp-includes/class-wp-meta-query.php
@@ -239,7 +239,7 @@ class WP_Meta_Query {
 		 * the rest of the meta_query).
 		 */
 		$primary_meta_query = array();
-		foreach ( array( 'key', 'compare', 'type', 'compare_key' ) as $key ) {
+		foreach ( array( 'key', 'compare', 'type', 'compare_key', 'type_key' ) as $key ) {
 			if ( ! empty( $qv[ "meta_$key" ] ) ) {
 				$primary_meta_query[ $key ] = $qv[ "meta_$key" ];
 			}
@@ -521,9 +521,27 @@ class WP_Meta_Query {
 			$clause['compare'] = '=';
 		}
 
-		if ( isset( $clause['compare_key'] ) && 'LIKE' === strtoupper( $clause['compare_key'] ) ) {
+		if ( isset( $clause['compare_key'] ) ) {
 			$clause['compare_key'] = strtoupper( $clause['compare_key'] );
 		} else {
+			$clause['compare_key'] = isset( $clause['key'] ) && is_array( $clause['key'] ) ? 'IN' : '=';
+		}
+
+		if ( ! in_array(
+			$clause['compare_key'], array(
+				'=',
+				'!=',
+				'LIKE',
+				'NOT LIKE',
+				'IN',
+				'NOT IN',
+				'EXISTS',
+				'NOT EXISTS',
+				'RLIKE',
+				'REGEXP',
+				'NOT REGEXP',
+			)
+		) ) {
 			$clause['compare_key'] = '=';
 		}
 
@@ -592,11 +610,93 @@ class WP_Meta_Query {
 			if ( 'NOT EXISTS' === $meta_compare ) {
 				$sql_chunks['where'][] = $alias . '.' . $this->meta_id_column . ' IS NULL';
 			} else {
-				if ( 'LIKE' === $meta_compare_key ) {
-					$sql_chunks['where'][] = $wpdb->prepare( "$alias.meta_key LIKE %s", '%' . $wpdb->esc_like( trim( $clause['key'] ) ) . '%' );
-				} else {
-					$sql_chunks['where'][] = $wpdb->prepare( "$alias.meta_key = %s", trim( $clause['key'] ) );
+				/**
+				 * Reusable clauses for negative operators.
+				 */
+				if ( in_array( $meta_compare_key, array( '!=', 'NOT IN', 'NOT LIKE', 'NOT EXISTS', 'NOT REGEXP' ) ) ) {
+					$i     = count( $this->table_aliases );
+					$subquery_alias = $i ? 'mt' . $i : $this->meta_table;
+					$this->table_aliases[] = $subquery_alias;
+
+					$meta_compare_string_start = "NOT EXISTS (";
+					$meta_compare_string_start    .= "SELECT 1 FROM $wpdb->postmeta $subquery_alias ";
+					$meta_compare_string_start    .= "WHERE $subquery_alias.post_ID = $alias.post_ID ";
+					// Subquery operator clause goes here
+					$meta_compare_string_end       = 'LIMIT 1';
+					$meta_compare_string_end   .= ")";
 				}
+
+				switch ( $meta_compare_key ) {
+					case '=':
+					case 'EXISTS':
+						$where = $wpdb->prepare( "$alias.meta_key = %s", trim( $clause['key'] ) );
+						break;
+					case 'LIKE':
+						$meta_compare_value = '%' . $wpdb->esc_like( trim( $clause['key'] ) ) . '%';
+						$where = $wpdb->prepare( "$alias.meta_key LIKE %s", $meta_compare_value );
+						break;
+					case 'IN':
+						$operator = $meta_compare_key;
+						$meta_compare_string = "$alias.meta_key $operator (" . substr( str_repeat( ',%s', count( $clause['key'] ) ), 1 ) . ')';
+						$where = $wpdb->prepare( $meta_compare_string, $clause['key'] );
+						break;
+					case 'RLIKE':
+					case 'REGEXP':
+						$operator = $meta_compare_key;
+						if ( isset( $clause['type_key'] ) && strtoupper( $clause['type_key'] ) == 'BINARY' ) {
+							$cast = 'BINARY';
+						} else {
+							$cast = '';
+						}
+						$where = $wpdb->prepare( "$alias.meta_key $operator $cast %s", trim( $clause['key'] ) );
+						break;
+
+					/**
+					 * In joined clauses negative operators have to be nested
+					 * into a NOT EXISTS clause and flipped. Otherwise, non-matching results
+					 * containing the post_IDs will be returned, rendering the
+					 * operator ineffective.
+					 */
+					case '!=':
+					case 'NOT EXISTS':
+						$meta_compare_string = $meta_compare_string_start
+						                     . "AND $subquery_alias.meta_key = %s "
+						                     . $meta_compare_string_end;
+						$where = $wpdb->prepare( $meta_compare_string, $clause['key'] );
+						break;
+					case 'NOT LIKE':
+						$meta_compare_string = $meta_compare_string_start
+						                     . "AND $subquery_alias.meta_key LIKE %s "
+						                     . $meta_compare_string_end;
+
+						$meta_compare_value = '%' . $wpdb->esc_like( trim( $clause['key'] ) ) . '%';
+						$where = $wpdb->prepare( $meta_compare_string, $meta_compare_value );
+						break;
+					case 'NOT IN':
+						$meta_compare_string = $meta_compare_string_start
+						                     . "AND $subquery_alias.meta_key IN "
+						                     . '(' . substr( str_repeat( ',%s', count( $clause['key'] ) ), 1 ) . ') '
+						                     . $meta_compare_string_end;
+
+						$where = $wpdb->prepare( $meta_compare_string, $clause['key'] );
+						break;
+					case 'NOT REGEXP':
+						$operator = $meta_compare_key;
+						if ( isset( $clause['type_key'] ) && strtoupper( $clause['type_key'] ) == 'BINARY' ) {
+							$cast = 'BINARY';
+						} else {
+							$cast = '';
+						}
+
+						$meta_compare_string = $meta_compare_string_start
+						                     . "AND $subquery_alias.meta_key REGEXP $cast %s "
+						                     . $meta_compare_string_end;
+
+						$where = $wpdb->prepare( $meta_compare_string, $clause['key'] );
+						break;
+				}
+
+				$sql_chunks['where'][] = $where;
 			}
 		}
 
