diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 086dadcf5b7b96d0de0094fd7d4cdbe80fd7d455..9f3ca385d93f530725590499ac342c8c2be0b2ce 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -15,7 +15,8 @@
 #     state: 'opened' or 'closed' or 'locked' or 'all'
 #     group_id: integer
 #     project_id: integer
-#     milestone_title: string
+#     milestone_title: string (cannot be simultaneously used with milestone_wildcard_id)
+#     milestone_wildcard_id: 'none', 'any', 'upcoming', 'started' (cannot be simultaneously used with milestone_title)
 #     release_tag: string
 #     author_id: integer
 #     author_username: string
diff --git a/app/finders/issuable_finder/params.rb b/app/finders/issuable_finder/params.rb
index 51e12dde51dd64590441b23998e804cf64962875..595f4e4cf8aada308b02c8a8cd41f6d93ddd3c4c 100644
--- a/app/finders/issuable_finder/params.rb
+++ b/app/finders/issuable_finder/params.rb
@@ -4,9 +4,11 @@ class IssuableFinder
   class Params < SimpleDelegator
     include Gitlab::Utils::StrongMemoize
 
-    # This is used as a common filter for None / Any
+    # This is used as a common filter for None / Any / Upcoming / Started
     FILTER_NONE = 'none'
     FILTER_ANY = 'any'
+    FILTER_STARTED = 'started'
+    FILTER_UPCOMING = 'upcoming'
 
     # This is used in unassigning users
     NONE = '0'
@@ -42,25 +44,35 @@ def labels?
     end
 
     def milestones?
-      params[:milestone_title].present?
+      params[:milestone_title].present? || params[:milestone_wildcard_id].present?
     end
 
     def filter_by_no_milestone?
-      # Accepts `No Milestone` for compatibility
-      params[:milestone_title].to_s.downcase == FILTER_NONE || params[:milestone_title] == Milestone::None.title
+      # Usage of `No Milestone` and `none`/`None` in milestone_title to be deprecated
+      # https://gitlab.com/gitlab-org/gitlab/-/issues/336044
+      params[:milestone_title].to_s.downcase == FILTER_NONE ||
+        params[:milestone_title] == Milestone::None.title ||
+        params[:milestone_wildcard_id].to_s.downcase == FILTER_NONE
     end
 
     def filter_by_any_milestone?
-      # Accepts `Any Milestone` for compatibility
-      params[:milestone_title].to_s.downcase == FILTER_ANY || params[:milestone_title] == Milestone::Any.title
+      # Usage of `Any Milestone` and `any`/`Any` in milestone_title to be deprecated
+      # https://gitlab.com/gitlab-org/gitlab/-/issues/336044
+      params[:milestone_title].to_s.downcase == FILTER_ANY ||
+        params[:milestone_title] == Milestone::Any.title ||
+        params[:milestone_wildcard_id].to_s.downcase == FILTER_ANY
     end
 
     def filter_by_upcoming_milestone?
-      params[:milestone_title] == Milestone::Upcoming.name
+      # Usage of `#upcoming` in milestone_title to be deprecated
+      # https://gitlab.com/gitlab-org/gitlab/-/issues/336044
+      params[:milestone_title] == Milestone::Upcoming.name || params[:milestone_wildcard_id].to_s.downcase == FILTER_UPCOMING
     end
 
     def filter_by_started_milestone?
-      params[:milestone_title] == Milestone::Started.name
+      # Usage of `#started` in milestone_title to be deprecated
+      # https://gitlab.com/gitlab-org/gitlab/-/issues/336044
+      params[:milestone_title] == Milestone::Started.name || params[:milestone_wildcard_id].to_s.downcase == FILTER_STARTED
     end
 
     def filter_by_no_release?
diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb
index 40d6730d232d5c3cc98b99b3207f470d986a662b..c5ffc29d4ef8de5a8461a0328e1b1ec9b828920b 100644
--- a/app/finders/issues_finder.rb
+++ b/app/finders/issues_finder.rb
@@ -11,7 +11,8 @@
 #     state: 'opened' or 'closed' or 'all'
 #     group_id: integer
 #     project_id: integer
-#     milestone_title: string
+#     milestone_title: string (cannot be simultaneously used with milestone_wildcard_id)
+#     milestone_wildcard_id: 'none', 'any', 'upcoming', 'started' (cannot be simultaneously used with milestone_title)
 #     assignee_id: integer
 #     search: string
 #     in: 'title', 'description', or a string joining them with comma
diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
index b91dca3fc47ae63eb6ec4e17005da086a1036d61..8d77c0f3a8d01586526035760a2d1fdb7d2bd64c 100644
--- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
+++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
@@ -56,6 +56,9 @@ module IssueResolverArguments
              as: :issue_types,
              description: 'Filter issues by the given issue types.',
              required: false
+    argument :milestone_wildcard_id, ::Types::MilestoneWildcardIdEnum,
+              required: false,
+              description: 'Filter issues by milestone ID wildcard.'
     argument :not, Types::Issues::NegatedIssueFilterInputType,
              description: 'Negated arguments.',
              prepare: ->(negated_args, ctx) { negated_args.to_h },
@@ -82,10 +85,9 @@ def resolve_with_lookahead(**args)
   end
 
   def ready?(**args)
-    if args.slice(*mutually_exclusive_assignee_username_args).compact.size > 1
-      arg_str = mutually_exclusive_assignee_username_args.map { |x| x.to_s.camelize(:lower) }.join(', ')
-      raise Gitlab::Graphql::Errors::ArgumentError, "only one of [#{arg_str}] arguments is allowed at the same time."
-    end
+    params_not_mutually_exclusive(args, mutually_exclusive_assignee_username_args)
+    params_not_mutually_exclusive(args, mutually_exclusive_milestone_args)
+    params_not_mutually_exclusive(args.fetch(:not, {}), mutually_exclusive_milestone_args)
 
     super
   end
@@ -106,6 +108,17 @@ def prepare_assignee_username_params(args)
     args[:not][:assignee_username] = args[:not].delete(:assignee_usernames) if args.dig(:not, :assignee_usernames).present?
   end
 
+  def params_not_mutually_exclusive(args, mutually_exclusive_args)
+    if args.slice(*mutually_exclusive_args).compact.size > 1
+      arg_str = mutually_exclusive_args.map { |x| x.to_s.camelize(:lower) }.join(', ')
+      raise ::Gitlab::Graphql::Errors::ArgumentError, "only one of [#{arg_str}] arguments is allowed at the same time."
+    end
+  end
+
+  def mutually_exclusive_milestone_args
+    [:milestone_title, :milestone_wildcard_id]
+  end
+
   def mutually_exclusive_assignee_username_args
     [:assignee_usernames, :assignee_username]
   end
diff --git a/app/graphql/types/issues/negated_issue_filter_input_type.rb b/app/graphql/types/issues/negated_issue_filter_input_type.rb
index 201b1ee6b977330c67cadb26476cc693e3b18d7b..e5125c554a4e560311a120e1f89b949172776407 100644
--- a/app/graphql/types/issues/negated_issue_filter_input_type.rb
+++ b/app/graphql/types/issues/negated_issue_filter_input_type.rb
@@ -20,6 +20,9 @@ class NegatedIssueFilterInputType < BaseInputObject
       argument :assignee_id, GraphQL::Types::String,
                 required: false,
                 description: 'ID of a user not assigned to the issues.'
+      argument :milestone_wildcard_id, ::Types::NegatedMilestoneWildcardIdEnum,
+                required: false,
+                description: 'Filter by negated milestone wildcard values.'
     end
   end
 end
diff --git a/app/graphql/types/milestone_wildcard_id_enum.rb b/app/graphql/types/milestone_wildcard_id_enum.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b5b339b1e5b77d8ea17504b72295e599acc83c14
--- /dev/null
+++ b/app/graphql/types/milestone_wildcard_id_enum.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Types
+  class MilestoneWildcardIdEnum < BaseEnum
+    graphql_name 'MilestoneWildcardId'
+    description 'Milestone ID wildcard values'
+
+    value 'NONE', 'No milestone is assigned.'
+    value 'ANY', 'A milestone is assigned.'
+    value 'STARTED', 'An open, started milestone (start date <= today).'
+    value 'UPCOMING', 'An open milestone due in the future (due date >= today).'
+  end
+end
diff --git a/app/graphql/types/negated_milestone_wildcard_id_enum.rb b/app/graphql/types/negated_milestone_wildcard_id_enum.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ca27a6c7b6edf9c7cb86d33277c81a5b17f5aa05
--- /dev/null
+++ b/app/graphql/types/negated_milestone_wildcard_id_enum.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Types
+  class NegatedMilestoneWildcardIdEnum < BaseEnum
+    graphql_name 'NegatedMilestoneWildcardId'
+    description 'Negated Milestone ID wildcard values'
+
+    value 'STARTED', 'An open, started milestone (start date <= today).'
+    value 'UPCOMING', 'An open milestone due in the future (due date >= today).'
+  end
+end
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 4e0147815cb32e54bd2586d899a88dbb0270bcdd..68c5dd46db5bdfed123bca0fea5aa60e50f1da5e 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -9662,6 +9662,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
 | <a id="groupissuesiterationwildcardid"></a>`iterationWildcardId` | [`IterationWildcardId`](#iterationwildcardid) | Filter by iteration ID wildcard. |
 | <a id="groupissueslabelname"></a>`labelName` | [`[String]`](#string) | Labels applied to this issue. |
 | <a id="groupissuesmilestonetitle"></a>`milestoneTitle` | [`[String]`](#string) | Milestone applied to this issue. |
+| <a id="groupissuesmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. |
 | <a id="groupissuesnot"></a>`not` | [`NegatedIssueFilterInput`](#negatedissuefilterinput) | Negated arguments. |
 | <a id="groupissuessearch"></a>`search` | [`String`](#string) | Search query for issue title or description. |
 | <a id="groupissuessort"></a>`sort` | [`IssueSort`](#issuesort) | Sort issues by this criteria. |
@@ -11902,6 +11903,7 @@ Returns [`Issue`](#issue).
 | <a id="projectissueiterationwildcardid"></a>`iterationWildcardId` | [`IterationWildcardId`](#iterationwildcardid) | Filter by iteration ID wildcard. |
 | <a id="projectissuelabelname"></a>`labelName` | [`[String]`](#string) | Labels applied to this issue. |
 | <a id="projectissuemilestonetitle"></a>`milestoneTitle` | [`[String]`](#string) | Milestone applied to this issue. |
+| <a id="projectissuemilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. |
 | <a id="projectissuenot"></a>`not` | [`NegatedIssueFilterInput`](#negatedissuefilterinput) | Negated arguments. |
 | <a id="projectissuesearch"></a>`search` | [`String`](#string) | Search query for issue title or description. |
 | <a id="projectissuesort"></a>`sort` | [`IssueSort`](#issuesort) | Sort issues by this criteria. |
@@ -11933,6 +11935,7 @@ Returns [`IssueStatusCountsType`](#issuestatuscountstype).
 | <a id="projectissuestatuscountsiids"></a>`iids` | [`[String!]`](#string) | List of IIDs of issues. For example, `["1", "2"]`. |
 | <a id="projectissuestatuscountslabelname"></a>`labelName` | [`[String]`](#string) | Labels applied to this issue. |
 | <a id="projectissuestatuscountsmilestonetitle"></a>`milestoneTitle` | [`[String]`](#string) | Milestone applied to this issue. |
+| <a id="projectissuestatuscountsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. |
 | <a id="projectissuestatuscountsnot"></a>`not` | [`NegatedIssueFilterInput`](#negatedissuefilterinput) | Negated arguments. |
 | <a id="projectissuestatuscountssearch"></a>`search` | [`String`](#string) | Search query for issue title or description. |
 | <a id="projectissuestatuscountstypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter issues by the given issue types. |
@@ -11968,6 +11971,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
 | <a id="projectissuesiterationwildcardid"></a>`iterationWildcardId` | [`IterationWildcardId`](#iterationwildcardid) | Filter by iteration ID wildcard. |
 | <a id="projectissueslabelname"></a>`labelName` | [`[String]`](#string) | Labels applied to this issue. |
 | <a id="projectissuesmilestonetitle"></a>`milestoneTitle` | [`[String]`](#string) | Milestone applied to this issue. |
+| <a id="projectissuesmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. |
 | <a id="projectissuesnot"></a>`not` | [`NegatedIssueFilterInput`](#negatedissuefilterinput) | Negated arguments. |
 | <a id="projectissuessearch"></a>`search` | [`String`](#string) | Search query for issue title or description. |
 | <a id="projectissuessort"></a>`sort` | [`IssueSort`](#issuesort) | Sort issues by this criteria. |
@@ -15044,6 +15048,17 @@ Current state of milestone.
 | <a id="milestonestateenumactive"></a>`active` | Milestone is currently active. |
 | <a id="milestonestateenumclosed"></a>`closed` | Milestone is closed. |
 
+### `MilestoneWildcardId`
+
+Milestone ID wildcard values.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="milestonewildcardidany"></a>`ANY` | A milestone is assigned. |
+| <a id="milestonewildcardidnone"></a>`NONE` | No milestone is assigned. |
+| <a id="milestonewildcardidstarted"></a>`STARTED` | An open, started milestone (start date <= today). |
+| <a id="milestonewildcardidupcoming"></a>`UPCOMING` | An open milestone due in the future (due date >= today). |
+
 ### `MoveType`
 
 The position to which the adjacent object should be moved.
@@ -15080,6 +15095,15 @@ Negated Iteration ID wildcard values.
 | ----- | ----------- |
 | <a id="negatediterationwildcardidcurrent"></a>`CURRENT` | Current iteration. |
 
+### `NegatedMilestoneWildcardId`
+
+Negated Milestone ID wildcard values.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="negatedmilestonewildcardidstarted"></a>`STARTED` | An open, started milestone (start date <= today). |
+| <a id="negatedmilestonewildcardidupcoming"></a>`UPCOMING` | An open milestone due in the future (due date >= today). |
+
 ### `NetworkPolicyKind`
 
 Kind of the network policy.
@@ -16774,6 +16798,7 @@ Represents an escalation rule.
 | <a id="negatedissuefilterinputiterationwildcardid"></a>`iterationWildcardId` | [`IterationWildcardId`](#iterationwildcardid) | Filter by negated iteration ID wildcard. |
 | <a id="negatedissuefilterinputlabelname"></a>`labelName` | [`[String!]`](#string) | Labels not applied to this issue. |
 | <a id="negatedissuefilterinputmilestonetitle"></a>`milestoneTitle` | [`[String!]`](#string) | Milestone not applied to this issue. |
+| <a id="negatedissuefilterinputmilestonewildcardid"></a>`milestoneWildcardId` | [`NegatedMilestoneWildcardId`](#negatedmilestonewildcardid) | Filter by negated milestone wildcard values. |
 | <a id="negatedissuefilterinputweight"></a>`weight` | [`String`](#string) | Weight not applied to the issue. |
 
 ### `OncallRotationActivePeriodInputType`
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index 89e4e803fa821166729a82e1ad5265ee6558cd0e..d0675633a9b161bbca6db7c695d17835f5df411b 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -11,9 +11,9 @@
   let_it_be(:project)       { create(:project, group: group) }
   let_it_be(:other_project) { create(:project, group: group) }
 
-  let_it_be(:milestone) { create(:milestone, project: project) }
+  let_it_be(:started_milestone) { create(:milestone, project: project, title: "started milestone", start_date: 1.day.ago) }
   let_it_be(:assignee)  { create(:user) }
-  let_it_be(:issue1)    { create(:incident, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago, milestone: milestone) }
+  let_it_be(:issue1)    { create(:incident, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago, milestone: started_milestone) }
   let_it_be(:issue2)    { create(:issue, project: project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) }
   let_it_be(:issue3)    { create(:issue, project: other_project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) }
   let_it_be(:issue4)    { create(:issue) }
@@ -43,7 +43,63 @@
       end
 
       it 'filters by milestone' do
-        expect(resolve_issues(milestone_title: [milestone.title])).to contain_exactly(issue1)
+        expect(resolve_issues(milestone_title: [started_milestone.title])).to contain_exactly(issue1)
+      end
+
+      describe 'filtering by milestone wildcard id' do
+        let_it_be(:upcoming_milestone) { create(:milestone, project: project, title: "upcoming milestone", start_date: 1.day.ago, due_date: 1.day.from_now) }
+        let_it_be(:past_milestone) { create(:milestone, project: project, title: "past milestone", due_date: 1.day.ago) }
+        let_it_be(:future_milestone) { create(:milestone, project: project, title: "future milestone", start_date: 1.day.from_now) }
+        let_it_be(:issue5) { create(:issue, project: project, state: :opened, milestone: upcoming_milestone) }
+        let_it_be(:issue6) { create(:issue, project: project, state: :opened, milestone: past_milestone) }
+        let_it_be(:issue7) { create(:issue, project: project, state: :opened, milestone: future_milestone) }
+
+        let(:wildcard_started) { 'STARTED' }
+        let(:wildcard_upcoming) { 'UPCOMING' }
+        let(:wildcard_any) { 'ANY' }
+        let(:wildcard_none) { 'NONE' }
+
+        it 'returns issues with started milestone' do
+          expect(resolve_issues(milestone_wildcard_id: wildcard_started)).to contain_exactly(issue1, issue5)
+        end
+
+        it 'returns issues with upcoming milestone' do
+          expect(resolve_issues(milestone_wildcard_id: wildcard_upcoming)).to contain_exactly(issue5)
+        end
+
+        it 'returns issues with any milestone' do
+          expect(resolve_issues(milestone_wildcard_id: wildcard_any)).to contain_exactly(issue1, issue5, issue6, issue7)
+        end
+
+        it 'returns issues with no milestone' do
+          expect(resolve_issues(milestone_wildcard_id: wildcard_none)).to contain_exactly(issue2)
+        end
+
+        it 'raises a mutually exclusive filter error when wildcard and title are provided' do
+          expect do
+            resolve_issues(milestone_title: ["started milestone"], milestone_wildcard_id: wildcard_started)
+          end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'only one of [milestoneTitle, milestoneWildcardId] arguments is allowed at the same time.')
+        end
+
+        context 'negated filtering' do
+          it 'returns issues matching the searched title after applying a negated filter' do
+            expect(resolve_issues(milestone_title: ['past milestone'], not: { milestone_wildcard_id: wildcard_upcoming })).to contain_exactly(issue6)
+          end
+
+          it 'returns issues excluding the ones with started milestone' do
+            expect(resolve_issues(not: { milestone_wildcard_id: wildcard_started })).to contain_exactly(issue7)
+          end
+
+          it 'returns issues excluding the ones with upcoming milestone' do
+            expect(resolve_issues(not: { milestone_wildcard_id: wildcard_upcoming })).to contain_exactly(issue6)
+          end
+
+          it 'raises a mutually exclusive filter error when wildcard and title are provided as negated filters' do
+            expect do
+              resolve_issues(not: { milestone_title: ["started milestone"], milestone_wildcard_id: wildcard_started })
+            end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, 'only one of [milestoneTitle, milestoneWildcardId] arguments is allowed at the same time.')
+          end
+        end
       end
 
       it 'filters by two assignees' do
@@ -169,7 +225,7 @@
         end
 
         it 'returns issues without the specified milestone' do
-          expect(resolve_issues(not: { milestone_title: [milestone.title] })).to contain_exactly(issue2)
+          expect(resolve_issues(not: { milestone_title: [started_milestone.title] })).to contain_exactly(issue2)
         end
 
         it 'returns issues without the specified assignee_usernames' do