diff --git a/includes/admin/class-activator.php b/includes/admin/class-activator.php
index a34c30a..108d892 100644
--- a/includes/admin/class-activator.php
+++ b/includes/admin/class-activator.php
@@ -18,6 +18,9 @@
  */
 class Activator {
 
+	private const TABLE_NAME       = 'bsearch';
+	private const TABLE_NAME_DAILY = 'bsearch_daily';
+
 	/**
 	 * Constructor class.
 	 *
@@ -70,8 +73,8 @@ public static function activation_hook( $network_wide ) {
 	public static function single_activate() {
 		global $wpdb;
 
-		$table_name       = $wpdb->prefix . 'bsearch';
-		$table_name_daily = $wpdb->prefix . 'bsearch_daily';
+		$table_name       = $wpdb->prefix . self::TABLE_NAME;
+		$table_name_daily = $wpdb->prefix . self::TABLE_NAME_DAILY;
 
 		// Create FULLTEXT indexes.
 		$wpdb->hide_errors();
@@ -199,6 +202,25 @@ public static function check_fulltext_indexes() {
 		return apply_filters( 'bsearch_fulltext_index_statuses', $statuses );
 	}
 
+	/**
+	 * Check if all fulltext indexes are installed.
+	 *
+	 * @since 4.0.0
+	 *
+	 * @return bool True if all fulltext indexes are installed, false if any are missing.
+	 */
+	public static function is_fulltext_index_installed() {
+		$indexes = self::get_fulltext_indexes();
+
+		foreach ( $indexes as $index => $columns ) {
+			if ( ! self::is_index_installed( $index ) ) {
+				return false; // Return false if any index is missing.
+			}
+		}
+
+		return true; // Return true if all indexes are installed.
+	}
+
 	/**
 	 * Create table if not exists.
 	 *
@@ -229,8 +251,9 @@ public static function create_full_table_sql() {
 		global $wpdb;
 
 		$charset_collate = $wpdb->get_charset_collate();
+		$table_name      = $wpdb->prefix . self::TABLE_NAME;
 
-		$sql = "CREATE TABLE {$wpdb->prefix}bsearch" . // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange
+		$sql = "CREATE TABLE {$table_name}" . // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange
 		" (
 			searchvar VARCHAR(100) NOT NULL,
 			cntaccess int NOT NULL,
@@ -251,8 +274,9 @@ public static function create_daily_table_sql() {
 		global $wpdb;
 
 		$charset_collate = $wpdb->get_charset_collate();
+		$table_name      = $wpdb->prefix . self::TABLE_NAME_DAILY;
 
-		$sql = "CREATE TABLE {$wpdb->prefix}bsearch_daily" . // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange
+		$sql = "CREATE TABLE {$table_name}" . // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange
 		" (
 			searchvar VARCHAR(100) NOT NULL,
 			cntaccess int NOT NULL,
@@ -331,7 +355,7 @@ public static function recreate_table( $table_name, $create_table_sql, $backup =
 	public static function recreate_overall_table( $backup = true ) {
 		global $wpdb;
 		return self::recreate_table(
-			$wpdb->prefix . 'bsearch',
+			$wpdb->prefix . self::TABLE_NAME,
 			self::create_full_table_sql(),
 			$backup
 		);
@@ -349,7 +373,7 @@ public static function recreate_overall_table( $backup = true ) {
 	public static function recreate_daily_table( $backup = true ) {
 		global $wpdb;
 		return self::recreate_table(
-			$wpdb->prefix . 'bsearch_daily',
+			$wpdb->prefix . self::TABLE_NAME_DAILY,
 			self::create_daily_table_sql(),
 			$backup,
 			array( 'searchvar', 'cntaccess', 'dp_date' ),
@@ -390,8 +414,8 @@ public static function activate_new_site( $blog ) {
 	public static function on_delete_blog( $tables ) {
 		global $wpdb;
 
-		$tables[] = $wpdb->prefix . 'bsearch';
-		$tables[] = $wpdb->prefix . 'bsearch_daily';
+		$tables[] = $wpdb->prefix . self::TABLE_NAME;
+		$tables[] = $wpdb->prefix . self::TABLE_NAME_DAILY;
 
 		return $tables;
 	}
diff --git a/includes/admin/class-admin-notices.php b/includes/admin/class-admin-notices.php
index 72de0ff..d73a407 100644
--- a/includes/admin/class-admin-notices.php
+++ b/includes/admin/class-admin-notices.php
@@ -25,6 +25,7 @@ class Admin_Notices {
 	 */
 	public function __construct() {
 		add_action( 'admin_init', array( $this, 'update_db_check' ) );
+		add_action( 'admin_notices', array( $this, 'fulltext_index_notice' ) );
 	}
 
 	/**
@@ -66,4 +67,29 @@ public function update_db_notice() {
 		</div>
 		<?php
 	}
+
+	/**
+	 * Display admin notice if the fulltext indexes are not created.
+	 *
+	 * @since 4.0.0
+	 */
+	public function fulltext_index_notice() {
+		if ( ! current_user_can( 'manage_options' ) || ! \bsearch_get_option( 'use_fulltext' ) ) {
+			return;
+		}
+
+		// Check if all indexes are installed.
+		if ( ! Activator::is_fulltext_index_installed() ) {
+			?>
+			<div class="notice notice-warning">
+				<p>
+					<?php esc_html_e( 'Better Search: Some fulltext indexes are missing, which will affect search results.', 'better-search' ); ?>
+					<a href="<?php echo esc_url( admin_url( 'admin.php?page=bsearch_tools_page' ) ); ?>">
+						<?php esc_html_e( 'Click here to recreate indexes.', 'better-search' ); ?>
+					</a>
+				</p>
+			</div>
+			<?php
+		}
+	}
 }
diff --git a/readme.txt b/readme.txt
index 601b363..d86c68c 100644
--- a/readme.txt
+++ b/readme.txt
@@ -120,6 +120,7 @@ You can report security bugs through the Patchstack Vulnerability Disclosure Pro
 * Enhancements/Modifications:
 	* Renamed `Better_Search` to `Better_Search_Core_Query`. Each of the methods now remove the filter from itself. It will also automatically parse wp_query parameters.
 	* Updated `Better_Search_Core_Query` filters to use the class instead of `WP_Query`.
+	* Display an admin notice if any of the fulltext indexes are missing and **Enable mySQL FULLTEXT searching** is enabled. This is only shown to admins and cannot be dismissed until the indexes are created.
 	* [Pro] Added a new button to create the indexes and display the index status on the settings page under the **Search tab for Enable mySQL FULLTEXT searching**.