diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index b4760b5baaa8b50953770dbc57dc8691a55b1ee2..f30253eefe3e0bfb657be8fb686bca9bd5600ae8 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -38,6 +38,8 @@ module Ci
 
     acts_as_taggable
 
+    after_destroy :cleanup_runner_queue
+
     # Searches for runners matching the given query.
     #
     # This method uses ILIKE on PostgreSQL and LIKE on MySQL.
@@ -143,6 +145,12 @@ module Ci
 
     private
 
+    def cleanup_runner_queue
+      Gitlab::Redis.with do |redis|
+        redis.del(runner_queue_key)
+      end
+    end
+
     def runner_queue_key
       "runner:build_queue:#{self.token}"
     end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 7b993a454b72787f70af3148c7c5b47b8aa96ae9..6283673d7ae2098685a8779e5fbc5f6986718b7b 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -319,6 +319,25 @@ describe Ci::Runner, models: true do
     end
   end
 
+  describe '#destroy' do
+    let(:runner) { create(:ci_runner) }
+
+    context 'when there is a tick in the queue' do
+      let!(:queue_key) { runner.send(:runner_queue_key) }
+
+      before do
+        runner.tick_runner_queue
+        runner.destroy
+      end
+
+      it 'cleans up the queue' do
+        Gitlab::Redis.with do |redis|
+          expect(redis.get(queue_key)).to be_nil
+        end
+      end
+    end
+  end
+
   describe '.assignable_for' do
     let(:runner) { create(:ci_runner) }
     let(:project) { create(:project) }