diff --git a/app/graphql/mutations/todos/base_many.rb b/app/graphql/mutations/todos/base_many.rb
index 8d424a5823dda6342449df930a270492e603b98f..eb87c90e2a48a72348eb0ade07342a40d834b6ad 100644
--- a/app/graphql/mutations/todos/base_many.rb
+++ b/app/graphql/mutations/todos/base_many.rb
@@ -16,11 +16,11 @@ class BaseMany < ::Mutations::BaseMutation # rubocop:disable GraphQL/GraphqlName
         null: false,
         description: 'Updated to-do items.'
 
-      def resolve(ids:)
+      def resolve(ids:, **kwargs)
         check_update_limit!(amount: ids.size)
 
         todos = authorized_find_all_pending_by_current_user(model_ids_of(ids))
-        updated_ids = process_todos(todos)
+        updated_ids = process_todos(todos, **kwargs)
 
         {
           updated_ids: updated_ids,
diff --git a/app/graphql/mutations/todos/snooze_many.rb b/app/graphql/mutations/todos/snooze_many.rb
new file mode 100644
index 0000000000000000000000000000000000000000..13ea918ba5618c0b014259095d64e8ff4d9a637e
--- /dev/null
+++ b/app/graphql/mutations/todos/snooze_many.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Mutations
+  module Todos
+    class SnoozeMany < BaseMany
+      graphql_name 'TodoSnoozeMany'
+
+      argument :snooze_until,
+        ::Types::TimeType,
+        required: true,
+        description: 'Time until which the todos should be snoozed.'
+
+      private
+
+      def process_todos(todos, snooze_until:)
+        ::Todos::SnoozingService.new.snooze_todos(todos, snooze_until)
+      end
+
+      def todo_state_to_find
+        :pending
+      end
+    end
+  end
+end
diff --git a/app/graphql/mutations/todos/unsnooze_many.rb b/app/graphql/mutations/todos/unsnooze_many.rb
new file mode 100644
index 0000000000000000000000000000000000000000..342ae41a8c292d0813de00f1f48dfd3cc3248ed9
--- /dev/null
+++ b/app/graphql/mutations/todos/unsnooze_many.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Mutations
+  module Todos
+    class UnsnoozeMany < BaseMany
+      graphql_name 'TodoUnsnoozeMany'
+
+      private
+
+      def process_todos(todos)
+        ::Todos::SnoozingService.new.unsnooze_todos(todos)
+      end
+
+      def todo_state_to_find
+        :pending
+      end
+    end
+  end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index fe69314d34f8e6a272b4714d1b783a0898396bc9..e57974bc39c3ab2dc5012bdef03b3fc680df3ee4 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -149,6 +149,8 @@ class MutationType < BaseObject
     mount_mutation Mutations::Todos::RestoreMany
     mount_mutation Mutations::Todos::Snooze, experiment: { milestone: '17.4' }
     mount_mutation Mutations::Todos::UnSnooze, experiment: { milestone: '17.4' }
+    mount_mutation Mutations::Todos::SnoozeMany, experiment: { milestone: '17.9' }
+    mount_mutation Mutations::Todos::UnsnoozeMany, experiment: { milestone: '17.9' }
     mount_mutation Mutations::Snippets::Destroy
     mount_mutation Mutations::Snippets::Update
     mount_mutation Mutations::Snippets::Create
diff --git a/app/services/todos/snoozing_service.rb b/app/services/todos/snoozing_service.rb
index 106df80159c01323e7a34e6956d151def2375901..13242ea64e9bd0bcb766fb5787ca10cfd58d3cdd 100644
--- a/app/services/todos/snoozing_service.rb
+++ b/app/services/todos/snoozing_service.rb
@@ -5,7 +5,7 @@
 # Used for snoozing/un-snoozing todos
 #
 # Ex.
-#   SnoozingService.new.snooze(todo, 1.day.from_now)
+#   Todos::SnoozingService.new.snooze_todo(todo, 1.day.from_now)
 #
 module Todos
   class SnoozingService
@@ -24,5 +24,13 @@ def un_snooze_todo(todo)
         ServiceResponse.error(message: todo.errors.full_messages)
       end
     end
+
+    def snooze_todos(todos, snooze_until)
+      todos.batch_update(snoozed_until: snooze_until)
+    end
+
+    def unsnooze_todos(todos)
+      todos.batch_update(snoozed_until: nil)
+    end
   end
 end
diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md
index 38f1a4e58bcf8f683c1ac4069b4949ffedd65881..1f7ab374cc5ca599c6c1712cf51ebed50c39143b 100644
--- a/doc/api/graphql/reference/_index.md
+++ b/doc/api/graphql/reference/_index.md
@@ -10520,6 +10520,30 @@ Input type: `TodoSnoozeInput`
 | <a id="mutationtodosnoozeerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
 | <a id="mutationtodosnoozetodo"></a>`todo` | [`Todo!`](#todo) | Requested to-do item. |
 
+### `Mutation.todoSnoozeMany`
+
+DETAILS:
+**Introduced** in GitLab 17.9.
+**Status**: Experiment.
+
+Input type: `TodoSnoozeManyInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationtodosnoozemanyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationtodosnoozemanyids"></a>`ids` | [`[TodoID!]!`](#todoid) | Global IDs of the to-do items to process (a maximum of 100 is supported at once). |
+| <a id="mutationtodosnoozemanysnoozeuntil"></a>`snoozeUntil` | [`Time!`](#time) | Time until which the todos should be snoozed. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationtodosnoozemanyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationtodosnoozemanyerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationtodosnoozemanytodos"></a>`todos` | [`[Todo!]!`](#todo) | Updated to-do items. |
+
 ### `Mutation.todoUnSnooze`
 
 DETAILS:
@@ -10543,6 +10567,29 @@ Input type: `TodoUnSnoozeInput`
 | <a id="mutationtodounsnoozeerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
 | <a id="mutationtodounsnoozetodo"></a>`todo` | [`Todo!`](#todo) | Requested to-do item. |
 
+### `Mutation.todoUnsnoozeMany`
+
+DETAILS:
+**Introduced** in GitLab 17.9.
+**Status**: Experiment.
+
+Input type: `TodoUnsnoozeManyInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationtodounsnoozemanyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationtodounsnoozemanyids"></a>`ids` | [`[TodoID!]!`](#todoid) | Global IDs of the to-do items to process (a maximum of 100 is supported at once). |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationtodounsnoozemanyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationtodounsnoozemanyerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationtodounsnoozemanytodos"></a>`todos` | [`[Todo!]!`](#todo) | Updated to-do items. |
+
 ### `Mutation.todosMarkAllDone`
 
 Input type: `TodosMarkAllDoneInput`
diff --git a/spec/graphql/mutations/todos/snooze_many_spec.rb b/spec/graphql/mutations/todos/snooze_many_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..dd58cab6a03c5cf70bc2a35f23991c16849d7f3b
--- /dev/null
+++ b/spec/graphql/mutations/todos/snooze_many_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Todos::SnoozeMany, feature_category: :notifications do
+  include GraphqlHelpers
+
+  let_it_be(:user) { create(:user) }
+  let_it_be(:other_user) { create(:user) }
+  let_it_be(:todo1) { create(:todo, user: user, author: other_user, state: :pending) }
+  let_it_be(:todo2) { create(:todo, user: user, author: other_user, state: :pending) }
+  let_it_be(:done_todo) { create(:todo, user: user, author: other_user, state: :done) }
+  let_it_be(:other_user_todo) { create(:todo, user: other_user, author: user, state: :pending) }
+
+  let(:snooze_until) { 1.day.from_now }
+  let(:current_user) { user }
+
+  describe '#process_todos' do
+    subject(:mutation) do
+      described_class
+        .new(object: nil, context: query_context, field: nil)
+        .resolve(ids: [
+          global_id_of(todo1),
+          global_id_of(done_todo),
+          global_id_of(other_user_todo)
+        ], snooze_until: snooze_until)
+    end
+
+    it 'snoozes current user\'s todos matching given ids until given timestamp' do
+      expect { mutation }.to change { todo1.reload.snoozed_until }.to be_within(1.second).of(snooze_until)
+    end
+
+    it 'does not change other pending todos of the current user' do
+      expect { mutation }.not_to change { todo2.reload.snoozed_until }
+    end
+
+    it 'does not change done todos' do
+      expect { mutation }.not_to change { done_todo.reload.snoozed_until }
+    end
+
+    it 'does not change todos of other users' do
+      expect { mutation }.not_to change { other_user_todo.reload.snoozed_until }
+    end
+
+    it 'returns the ids of processed todos' do
+      expect(mutation[:updated_ids]).to contain_exactly(todo1.id)
+    end
+  end
+end
diff --git a/spec/graphql/mutations/todos/unsnooze_many_spec.rb b/spec/graphql/mutations/todos/unsnooze_many_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f265cc09bdf6906588b2ef52b5e6a398ff790ed9
--- /dev/null
+++ b/spec/graphql/mutations/todos/unsnooze_many_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Todos::UnsnoozeMany, feature_category: :notifications do
+  include GraphqlHelpers
+
+  let_it_be(:user) { create(:user) }
+  let_it_be(:other_user) { create(:user) }
+  let_it_be(:snoozed_todo1) { create(:todo, user: user, author: other_user, snoozed_until: 8.hours.from_now) }
+  let_it_be(:snoozed_todo2) { create(:todo, user: user, author: other_user, snoozed_until: 5.days.from_now) }
+  let_it_be(:done_todo) { create(:todo, user: user, author: other_user, state: :done) }
+  let_it_be(:other_user_snoozed_todo) { create(:todo, user: other_user, author: user, snoozed_until: 1.hour.from_now) }
+
+  let(:current_user) { user }
+
+  describe '#process_todos' do
+    subject(:mutation) do
+      described_class
+        .new(object: nil, context: query_context, field: nil)
+        .resolve(ids: [
+          global_id_of(snoozed_todo1),
+          global_id_of(done_todo),
+          global_id_of(other_user_snoozed_todo)
+        ])
+    end
+
+    it 'unsnoozes current user\'s todos matching given ids until given timestamp' do
+      expect { mutation }.to change { snoozed_todo1.reload.snoozed_until }.to be_nil
+    end
+
+    it 'does not change other snoozed todos of the current user' do
+      expect { mutation }.not_to change { snoozed_todo2.reload.snoozed_until }
+    end
+
+    it 'does not change done todos' do
+      expect { mutation }.not_to change { done_todo.reload.snoozed_until }
+    end
+
+    it 'does not change todos of other users' do
+      expect { mutation }.not_to change { other_user_snoozed_todo.reload.snoozed_until }
+    end
+
+    it 'returns the ids of processed todos' do
+      expect(mutation[:updated_ids]).to contain_exactly(snoozed_todo1.id)
+    end
+  end
+end
diff --git a/spec/services/todos/snoozing_service_spec.rb b/spec/services/todos/snoozing_service_spec.rb
index 26a3e364eddd46f70d33382c402282095a20e754..bc5a48a0de376b3243fe9e4b61db0692b675abed 100644
--- a/spec/services/todos/snoozing_service_spec.rb
+++ b/spec/services/todos/snoozing_service_spec.rb
@@ -83,4 +83,43 @@
       end
     end
   end
+
+  describe '#snooze_todos' do
+    let_it_be(:time) { 8.hours.from_now }
+    let_it_be(:todo1) { create(:todo, :pending, user: user) }
+    let_it_be(:todo2) { create(:todo, :pending, user: user, snoozed_until: 1.hour.ago) }
+    let(:todos) { Todo.where(id: [todo1.id, todo2.id]) }
+
+    it 'snoozes all todos until the provided time' do
+      service.snooze_todos(todos, time)
+
+      expect(todo1.reload.snoozed_until).to be_within(1.second).of(time)
+      expect(todo2.reload.snoozed_until).to be_within(1.second).of(time)
+    end
+
+    it 'responds with the updated todo ids' do
+      response = service.snooze_todos(todos, time)
+
+      expect(response).to match_array [todo1.id, todo2.id]
+    end
+  end
+
+  describe '#unsnooze_todos' do
+    let_it_be(:todo1) { create(:todo, :pending, user: user, snoozed_until: 1.day.from_now) }
+    let_it_be(:todo2) { create(:todo, :pending, user: user, snoozed_until: nil) }
+    let(:todos) { Todo.where(id: [todo1.id, todo2.id]) }
+
+    it 'unsnoozes all todos' do
+      service.unsnooze_todos(todos)
+
+      expect(todo1.reload.snoozed_until).to be_nil
+      expect(todo2.reload.snoozed_until).to be_nil
+    end
+
+    it 'responds with the updated todo ids' do
+      response = service.unsnooze_todos(todos)
+
+      expect(response).to match_array [todo1.id, todo2.id]
+    end
+  end
 end