diff --git a/app/services/clusters/agent_tokens/create_service.rb b/app/services/clusters/agent_tokens/create_service.rb
index 66a3cb04d98084d020fdd2e1c31a980b10ec1bdf..efa9716d2c8483ab2bc3fdb082c20aa37f20ac31 100644
--- a/app/services/clusters/agent_tokens/create_service.rb
+++ b/app/services/clusters/agent_tokens/create_service.rb
@@ -4,6 +4,7 @@ module Clusters
   module AgentTokens
     class CreateService
       ALLOWED_PARAMS = %i[agent_id description name].freeze
+      ACTIVE_TOKENS_LIMIT = 2
 
       attr_reader :agent, :current_user, :params
 
@@ -15,6 +16,7 @@ def initialize(agent:, current_user:, params:)
 
       def execute
         return error_no_permissions unless current_user.can?(:create_cluster, agent.project)
+        return error_active_tokens_limit_reached if active_tokens_limit_reached?
 
         token = ::Clusters::AgentToken.new(filtered_params.merge(agent_id: agent.id, created_by_user: current_user))
 
@@ -33,6 +35,16 @@ def error_no_permissions
         ServiceResponse.error(message: s_('ClusterAgent|User has insufficient permissions to create a token for this project'))
       end
 
+      def error_active_tokens_limit_reached
+        ServiceResponse.error(message: s_('ClusterAgent|An agent can have only two active tokens at a time'))
+      end
+
+      def active_tokens_limit_reached?
+        return false unless Feature.enabled?(:cluster_agents_limit_tokens_created)
+
+        ::Clusters::AgentTokensFinder.new(agent, current_user, status: :active).execute.count >= ACTIVE_TOKENS_LIMIT
+      end
+
       def filtered_params
         params.slice(*ALLOWED_PARAMS)
       end
diff --git a/config/feature_flags/development/cluster_agents_limit_tokens_created.yml b/config/feature_flags/development/cluster_agents_limit_tokens_created.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1ad85185509e1bdd2eee2aa861dfe5c12f37a147
--- /dev/null
+++ b/config/feature_flags/development/cluster_agents_limit_tokens_created.yml
@@ -0,0 +1,8 @@
+---
+name: cluster_agents_limit_tokens_created
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120825
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/412399
+milestone: '16.1'
+type: development
+group: group::environments
+default_enabled: false
diff --git a/doc/api/cluster_agents.md b/doc/api/cluster_agents.md
index 4bd16b88d92ee210c9edc994665f4652ed857753..1753757e5d9929e4314e07e6294960b638a0be5b 100644
--- a/doc/api/cluster_agents.md
+++ b/doc/api/cluster_agents.md
@@ -365,12 +365,15 @@ Example response:
 
 ## Create an agent token
 
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/347046) in GitLab 15.0.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/347046) in GitLab 15.0.
+> - Two-token limit [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/361030) in GitLab 16.1.
 
 Creates a new token for an agent.
 
 You must have at least the Maintainer role to use this endpoint.
 
+An agent can have only two active tokens at one time.
+
 ```plaintext
 POST /projects/:id/cluster_agents/:agent_id/tokens
 ```
diff --git a/doc/user/clusters/agent/work_with_agent.md b/doc/user/clusters/agent/work_with_agent.md
index 2d54f67724e63c0820622bbc9b243361554321b0..b2e8ac6ef16b35a639a3b3a0df2e0c04a770b2dc 100644
--- a/doc/user/clusters/agent/work_with_agent.md
+++ b/doc/user/clusters/agent/work_with_agent.md
@@ -91,6 +91,9 @@ For more information about debugging, see [troubleshooting documentation](troubl
 
 > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/327152) in GitLab 14.9.
 > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336641) in GitLab 14.10, the agent token can be revoked from the UI.
+> - Two-token limit [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/361030) in GitLab 16.1.
+
+An agent can have only two active tokens at one time.
 
 To reset the agent token without downtime:
 
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index d88504345aee8392b7a7a09ab8188020ccbffa93..bf12efde8421d272ac1110952b830a66f3c03bbf 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -10415,6 +10415,9 @@ msgstr ""
 msgid "ClusterAgents|shared"
 msgstr ""
 
+msgid "ClusterAgent|An agent can have only two active tokens at a time"
+msgstr ""
+
 msgid "ClusterAgent|User has insufficient permissions to create a token for this project"
 msgstr ""
 
diff --git a/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb b/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb
index 7998be19c2007cd1ce232b723290f752e6ada838..cb01ff64d5d28675454e65cdc85021990fee29f2 100644
--- a/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb
+++ b/spec/graphql/mutations/clusters/agent_tokens/create_spec.rb
@@ -50,6 +50,18 @@
         expect(token.description).to eq(description)
         expect(token.name).to eq(name)
       end
+
+      context 'when the active agent tokens limit is reached' do
+        before do
+          create(:cluster_agent_token, agent: cluster_agent)
+          create(:cluster_agent_token, agent: cluster_agent)
+        end
+
+        it 'raises an error' do
+          expect { subject }.not_to change { ::Clusters::AgentToken.count }
+          expect(subject[:errors]).to eq(["An agent can have only two active tokens at a time"])
+        end
+      end
     end
   end
 end
diff --git a/spec/requests/api/clusters/agent_tokens_spec.rb b/spec/requests/api/clusters/agent_tokens_spec.rb
index 2647684c9f8120850f41a78b4207b302ccf004a0..c18ebf7d044362a35001a1d1b804386f0056c0fe 100644
--- a/spec/requests/api/clusters/agent_tokens_spec.rb
+++ b/spec/requests/api/clusters/agent_tokens_spec.rb
@@ -162,6 +162,28 @@
         expect(response).to have_gitlab_http_status(:forbidden)
       end
     end
+
+    context 'when the active agent tokens limit is reached' do
+      before do
+        # create an additional agent token to make it 2
+        create(:cluster_agent_token, agent: agent)
+      end
+
+      it 'returns a bad request (400) error' do
+        params = {
+          name: 'test-token',
+          description: 'Test description'
+        }
+        post(api("/projects/#{project.id}/cluster_agents/#{agent.id}/tokens", user), params: params)
+
+        aggregate_failures "testing response" do
+          expect(response).to have_gitlab_http_status(:bad_request)
+
+          error_message = json_response['message']
+          expect(error_message).to eq('400 Bad request - An agent can have only two active tokens at a time')
+        end
+      end
+    end
   end
 
   describe 'DELETE /projects/:id/cluster_agents/:agent_id/tokens/:token_id' do
diff --git a/spec/services/clusters/agent_tokens/create_service_spec.rb b/spec/services/clusters/agent_tokens/create_service_spec.rb
index 803bd947629b7dad9e13cd4610e03e2112b29fe7..431d7ce207994a44bdfd9be5bbedcc26f5c259d8 100644
--- a/spec/services/clusters/agent_tokens/create_service_spec.rb
+++ b/spec/services/clusters/agent_tokens/create_service_spec.rb
@@ -78,6 +78,33 @@
           expect(subject.message).to eq(["Name can't be blank"])
         end
       end
+
+      context 'when the active agent tokens limit is reached' do
+        before do
+          create(:cluster_agent_token, agent: cluster_agent)
+          create(:cluster_agent_token, agent: cluster_agent)
+        end
+
+        it 'returns an error' do
+          expect(subject.status).to eq(:error)
+          expect(subject.message).to eq('An agent can have only two active tokens at a time')
+        end
+
+        context 'when cluster_agents_limit_tokens_created feature flag is disabled' do
+          before do
+            stub_feature_flags(cluster_agents_limit_tokens_created: false)
+          end
+
+          it 'creates a new token' do
+            expect { subject }.to change { ::Clusters::AgentToken.count }.by(1)
+          end
+
+          it 'returns success status', :aggregate_failures do
+            expect(subject.status).to eq(:success)
+            expect(subject.message).to be_nil
+          end
+        end
+      end
     end
   end
 end