diff --git a/db/post_migrate/20241212144443_add_remove_dormant_members_idx_namespace_settings.rb b/db/post_migrate/20241212144443_add_remove_dormant_members_idx_namespace_settings.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c227b1a951d7ecd195d390464272afbcaa03d111
--- /dev/null
+++ b/db/post_migrate/20241212144443_add_remove_dormant_members_idx_namespace_settings.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class AddRemoveDormantMembersIdxNamespaceSettings < Gitlab::Database::Migration[2.2]
+  disable_ddl_transaction!
+  milestone '17.8'
+
+  COLUMNS = %i[last_dormant_member_review_at remove_dormant_members]
+  INDEX_NAME = 'idx_namespace_settings_on_remove_dormant_members_review_at'
+  TABLE = :namespace_settings
+
+  def up
+    add_concurrent_index(
+      TABLE,
+      COLUMNS,
+      where: 'remove_dormant_members IS true',
+      name: INDEX_NAME
+    )
+  end
+
+  def down
+    remove_concurrent_index(
+      TABLE,
+      COLUMNS,
+      name: INDEX_NAME
+    )
+  end
+end
diff --git a/db/post_migrate/20241212144777_remove_last_dormant_member_review_at_idx_namespace_settings.rb b/db/post_migrate/20241212144777_remove_last_dormant_member_review_at_idx_namespace_settings.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0c4bc493313301502320e03999ba725c9bee9741
--- /dev/null
+++ b/db/post_migrate/20241212144777_remove_last_dormant_member_review_at_idx_namespace_settings.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class RemoveLastDormantMemberReviewAtIdxNamespaceSettings < Gitlab::Database::Migration[2.2]
+  disable_ddl_transaction!
+
+  milestone '17.8'
+
+  INDEX_NAME = 'idx_namespace_settings_on_last_dormant_member_review_at'
+
+  def up
+    remove_concurrent_index :namespace_settings, :last_dormant_member_review_at, name: INDEX_NAME
+  end
+
+  def down
+    add_concurrent_index(
+      :namespace_settings, :last_dormant_member_review_at,
+      where: 'remove_dormant_members IS true',
+      name: INDEX_NAME
+    )
+  end
+end
diff --git a/db/schema_migrations/20241212144443 b/db/schema_migrations/20241212144443
new file mode 100644
index 0000000000000000000000000000000000000000..73dfb61e008ca19cf22839f6145593a8d7972623
--- /dev/null
+++ b/db/schema_migrations/20241212144443
@@ -0,0 +1 @@
+3762bf062f641523600b9899d2b77f51cc381df06e283492b8d3de0647b5fe11
\ No newline at end of file
diff --git a/db/schema_migrations/20241212144777 b/db/schema_migrations/20241212144777
new file mode 100644
index 0000000000000000000000000000000000000000..e2b307fe03ff400b4fa3b515e7c5ab87170ac27a
--- /dev/null
+++ b/db/schema_migrations/20241212144777
@@ -0,0 +1 @@
+521f5a1d38e9313554d8b054cb1539a8f5e5dd1713df7715d82ed92dd29938cc
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 9b6e01209fbc5a48033977846b2df1ad1bdb4601..c5859623774127b4e4e7878e6a3848e065caf654 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -29039,7 +29039,7 @@ CREATE INDEX idx_namespace_hostname_import_type_id_source_name_and_username ON i
 
 CREATE UNIQUE INDEX idx_namespace_settings_on_default_compliance_framework_id ON namespace_settings USING btree (default_compliance_framework_id);
 
-CREATE INDEX idx_namespace_settings_on_last_dormant_member_review_at ON namespace_settings USING btree (last_dormant_member_review_at) WHERE (remove_dormant_members IS TRUE);
+CREATE INDEX idx_namespace_settings_on_remove_dormant_members_review_at ON namespace_settings USING btree (last_dormant_member_review_at, remove_dormant_members) WHERE (remove_dormant_members IS TRUE);
 
 CREATE UNIQUE INDEX idx_o11y_log_issue_conn_on_issue_id_logs_search_metadata ON observability_logs_issues_connections USING btree (issue_id, service_name, severity_number, log_timestamp, log_fingerprint, trace_identifier);
 
diff --git a/ee/app/models/ee/namespace_setting.rb b/ee/app/models/ee/namespace_setting.rb
index 39b5f390978384ab57bca999542e557bb1119496..cb4ee5f7339dc1dab2748def1c09e68d2252c18f 100644
--- a/ee/app/models/ee/namespace_setting.rb
+++ b/ee/app/models/ee/namespace_setting.rb
@@ -6,8 +6,17 @@ module NamespaceSetting
     extend ::Gitlab::Utils::Override
 
     prepended do
+      DORMANT_REVIEW_PERIOD = 18.hours.ago
+
       cascading_attr :duo_features_enabled
 
+      scope :requiring_dormant_member_review, ->(limit) do
+        # look for settings that have not been reviewed in more than
+        # 18 hours (catering for 6-hourly review schedule)
+        where(remove_dormant_members: true)
+          .where('last_dormant_member_review_at < ? OR last_dormant_member_review_at IS NULL', DORMANT_REVIEW_PERIOD)
+          .limit(limit)
+      end
       scope :duo_features_set, ->(setting) { where(duo_features_enabled: setting) }
 
       belongs_to :default_compliance_framework, optional: true, class_name: "ComplianceManagement::Framework"
diff --git a/ee/spec/models/namespace_setting_spec.rb b/ee/spec/models/namespace_setting_spec.rb
index 5512e9371233ef31f17dc2ffd76e665c1711654a..445e1ce5eca66c300d05feb5b59c25141379c82a 100644
--- a/ee/spec/models/namespace_setting_spec.rb
+++ b/ee/spec/models/namespace_setting_spec.rb
@@ -16,6 +16,20 @@
     end
   end
 
+  describe 'scopes' do
+    describe '.requiring_dormant_member_review', :freeze_time do
+      it 'returns settings with feature enabled requiring review' do
+        setting_never_reviewed = create(:namespace_settings, remove_dormant_members: true, last_dormant_member_review_at: nil)
+        setting_reviewed_19_hours_ago = create(:namespace_settings, remove_dormant_members: true, last_dormant_member_review_at: 19.hours.ago)
+        create(:namespace_settings, last_dormant_member_review_at: 18.hours.ago) # exactly 18 hours ago
+        create(:namespace_settings, remove_dormant_members: false) # feature is disabled
+
+        expect(described_class.requiring_dormant_member_review(3))
+          .to contain_exactly(setting_never_reviewed, setting_reviewed_19_hours_ago)
+      end
+    end
+  end
+
   describe 'validations' do
     subject(:settings) { group.namespace_settings }