diff --git a/ee/config/feature_flags/ops/zoekt_critical_watermark_stop_indexing.yml b/ee/config/feature_flags/ops/zoekt_critical_watermark_stop_indexing.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c2f5f075a8a58cbafdb7f539e0088b19c0dff831
--- /dev/null
+++ b/ee/config/feature_flags/ops/zoekt_critical_watermark_stop_indexing.yml
@@ -0,0 +1,9 @@
+---
+name: zoekt_critical_watermark_stop_indexing
+feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/504945
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173167
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/505334
+milestone: '17.7'
+group: group::global search
+type: ops
+default_enabled: false
diff --git a/ee/lib/api/internal/search/zoekt.rb b/ee/lib/api/internal/search/zoekt.rb
index 9ea71e495a1309cca94f01c70e870f45c6032f8b..9e8aa6a23d68fd6b62b1247780728af708dcc6d6 100644
--- a/ee/lib/api/internal/search/zoekt.rb
+++ b/ee/lib/api/internal/search/zoekt.rb
@@ -39,6 +39,9 @@ def logger
                     { id: node.id, truncate: new_node }.tap do |resp|
                       resp[:tasks] = ::Search::Zoekt::TaskPresenterService.execute(node)
                       resp[:pull_frequency] = node.task_pull_frequency
+                      if Feature.enabled?(:zoekt_critical_watermark_stop_indexing)
+                        resp[:stop_indexing] = node.watermark_exceeded_critical?
+                      end
                     end
                   else
                     unprocessable_entity!
diff --git a/ee/spec/requests/api/internal/search/zoekt_spec.rb b/ee/spec/requests/api/internal/search/zoekt_spec.rb
index e0ef1e2a3a093ce8cd7b79eb33d40912e63e3383..bec93a0058f0ba2e1120f535194df0bc99b6b432 100644
--- a/ee/spec/requests/api/internal/search/zoekt_spec.rb
+++ b/ee/spec/requests/api/internal/search/zoekt_spec.rb
@@ -34,11 +34,16 @@
     context 'with valid auth' do
       subject(:request) { get api(endpoint), params: valid_params, headers: gitlab_shell_internal_api_request_header }
 
+      let(:node) { build(:zoekt_node) }
+
+      before do
+        allow(::Search::Zoekt::Node).to receive(:find_or_initialize_by_task_request)
+                                           .with(valid_params).and_return(node)
+      end
+
       context 'with feature flag disabled' do
         before do
           stub_feature_flags(zoekt_internal_api_register_nodes: false)
-          allow(::Search::Zoekt::Node).to receive(:find_or_initialize_by_task_request)
-            .with(valid_params).and_return(node)
         end
 
         context 'when node does not exist' do
@@ -52,7 +57,7 @@
             expect(response).to have_gitlab_http_status(:ok)
             expect(json_response).to eq(
               { 'id' => nil, 'tasks' => [], 'pull_frequency' => Search::Zoekt::Node::TASK_PULL_FREQUENCY_DEFAULT,
-                'truncate' => true }
+                'truncate' => true, 'stop_indexing' => false }
             )
           end
         end
@@ -68,7 +73,7 @@
             expect(response).to have_gitlab_http_status(:ok)
             expect(json_response).to eq(
               { 'id' => node.id, 'tasks' => [], 'pull_frequency' => Search::Zoekt::Node::TASK_PULL_FREQUENCY_DEFAULT,
-                'truncate' => false }
+                'truncate' => false, 'stop_indexing' => false }
             )
           end
         end
@@ -83,8 +88,6 @@
         end
 
         it 'returns node ID and tasks for task request' do
-          expect(::Search::Zoekt::Node).to receive(:find_or_initialize_by_task_request)
-            .with(valid_params).and_return(node)
           expect(node).to receive(:save).and_return(true)
 
           get api(endpoint), params: valid_params, headers: gitlab_shell_internal_api_request_header
@@ -92,7 +95,7 @@
           expect(response).to have_gitlab_http_status(:ok)
           expect(json_response).to eq(
             { 'id' => node.id, 'tasks' => tasks, 'pull_frequency' => Search::Zoekt::Node::TASK_PULL_FREQUENCY_DEFAULT,
-              'truncate' => true }
+              'truncate' => true, 'stop_indexing' => false }
           )
         end
 
@@ -102,8 +105,6 @@
           end
 
           it 'does not adds pull_frequency in the response' do
-            expect(::Search::Zoekt::Node).to receive(:find_or_initialize_by_task_request)
-                                               .with(valid_params).and_return(node)
             expect(node).to receive(:save).and_return(true)
 
             get api(endpoint), params: valid_params, headers: gitlab_shell_internal_api_request_header
@@ -111,16 +112,41 @@
             expect(::Search::Zoekt::TaskPresenterService).not_to receive(:execute)
             expect(response).to have_gitlab_http_status(:ok)
             expect(json_response).to eq({ 'id' => node.id, 'tasks' => tasks, 'truncate' => true,
-                                          'pull_frequency' =>  Search::Zoekt::Node::TASK_PULL_FREQUENCY_DEFAULT })
+                                          'pull_frequency' =>  Search::Zoekt::Node::TASK_PULL_FREQUENCY_DEFAULT,
+                                          'stop_indexing' => false })
+          end
+        end
+
+        context 'when node is over critical watermark' do
+          before do
+            allow(::Search::Zoekt::TaskPresenterService).to receive(:execute).with(node).and_return([])
+            allow(node).to receive_messages(save_debouce: true, watermark_exceeded_critical?: true)
+          end
+
+          it 'sets stop_indexing attribute in response to true' do
+            get api(endpoint), params: valid_params, headers: gitlab_shell_internal_api_request_header
+            expect(response).to have_gitlab_http_status(:ok)
+            expect(json_response).to include('stop_indexing' => true)
+          end
+
+          context 'when zoekt_critical_watermark_stop_indexing is disabled' do
+            before do
+              stub_feature_flags(zoekt_critical_watermark_stop_indexing: false)
+            end
+
+            it 'does not add stop_indexing in the response' do
+              get api(endpoint), params: valid_params, headers: gitlab_shell_internal_api_request_header
+              expect(response).to have_gitlab_http_status(:ok)
+              expect(json_response).not_to have_key('stop_indexing')
+            end
           end
         end
       end
 
       context 'when a heartbeat has valid params but a node validation error occurs' do
+        let(:node) { build(:zoekt_node, id: 123, search_base_url: nil) }
+
         it 'returns 422' do
-          node = ::Search::Zoekt::Node.new(search_base_url: nil) # null attributes makes this invalid
-          expect(::Search::Zoekt::Node).to receive(:find_or_initialize_by_task_request)
-            .with(valid_params).and_return(node)
           get api(endpoint), params: valid_params, headers: gitlab_shell_internal_api_request_header
           expect(response).to have_gitlab_http_status(:unprocessable_entity)
         end