diff --git a/app/services/ci/runners/assign_runner_service.rb b/app/services/ci/runners/assign_runner_service.rb
index 290f945cc7216c1e5e5aadbe0bf71a9657a0df45..4e7b08bdd7a1e9f06415223f2a3b544707c7d2db 100644
--- a/app/services/ci/runners/assign_runner_service.rb
+++ b/app/services/ci/runners/assign_runner_service.rb
@@ -17,6 +17,10 @@ def execute
           return ServiceResponse.error(message: 'user not allowed to assign runner', http_status: :forbidden)
         end
 
+        unless @user.can?(:register_project_runners, @project)
+          return ServiceResponse.error(message: 'user not allowed to add runners to project', http_status: :forbidden)
+        end
+
         if @runner.assign_to(@project, @user)
           ServiceResponse.success
         else
diff --git a/spec/services/ci/runners/assign_runner_service_spec.rb b/spec/services/ci/runners/assign_runner_service_spec.rb
index 92f6db2bdfb389e65f27ee54c4ce37bbe3b6dec5..00fbb5e2d26a14c97f182286d18da1a962c0f865 100644
--- a/spec/services/ci/runners/assign_runner_service_spec.rb
+++ b/spec/services/ci/runners/assign_runner_service_spec.rb
@@ -3,10 +3,12 @@
 require 'spec_helper'
 
 RSpec.describe ::Ci::Runners::AssignRunnerService, '#execute', feature_category: :runner_fleet do
-  subject(:execute) { described_class.new(runner, project, user).execute }
+  subject(:execute) { described_class.new(runner, new_project, user).execute }
 
-  let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) }
-  let_it_be(:project) { create(:project) }
+  let_it_be(:owner_group) { create(:group) }
+  let_it_be(:owner_project) { create(:project, group: owner_group) }
+  let_it_be(:new_project) { create(:project) }
+  let_it_be(:runner) { create(:ci_runner, :project, projects: [owner_project]) }
 
   context 'without user' do
     let(:user) { nil }
@@ -30,11 +32,54 @@
     end
   end
 
+  context 'with authorized user' do
+    let(:user) { create(:user) }
+
+    context 'with user owning runner and being maintainer of new project' do
+      before do
+        owner_project.group.add_owner(user)
+        new_project.add_maintainer(user)
+      end
+
+      it 'calls assign_to on runner and returns success response' do
+        expect(runner).to receive(:assign_to).with(new_project, user).once.and_call_original
+
+        is_expected.to be_success
+      end
+    end
+
+    context 'with user owning runner' do
+      before do
+        owner_project.add_maintainer(user)
+      end
+
+      it 'does not call assign_to on runner and returns error message', :aggregate_failures do
+        expect(runner).not_to receive(:assign_to)
+
+        is_expected.to be_error
+        expect(execute.message).to eq('user not allowed to add runners to project')
+      end
+    end
+
+    context 'with user being maintainer of new project', :aggregate_failures do
+      before do
+        new_project.add_maintainer(user)
+      end
+
+      it 'does not call assign_to on runner and returns error message' do
+        expect(runner).not_to receive(:assign_to)
+
+        is_expected.to be_error
+        expect(execute.message).to eq('user not allowed to assign runner')
+      end
+    end
+  end
+
   context 'with admin user', :enable_admin_mode do
-    let(:user) { create_default(:user, :admin) }
+    let(:user) { create(:user, :admin) }
 
     it 'calls assign_to on runner and returns success response' do
-      expect(runner).to receive(:assign_to).with(project, user).once.and_call_original
+      expect(runner).to receive(:assign_to).with(new_project, user).once.and_call_original
 
       is_expected.to be_success
     end