diff --git a/files/gitlab-config-template/gitlab.rb.template b/files/gitlab-config-template/gitlab.rb.template
index 3eac49be9d0b76016ad458b726a85c1b296b0ca2_ZmlsZXMvZ2l0bGFiLWNvbmZpZy10ZW1wbGF0ZS9naXRsYWIucmIudGVtcGxhdGU=..221553a16e33b0f79d1a961dda043abcd1e85bf2_ZmlsZXMvZ2l0bGFiLWNvbmZpZy10ZW1wbGF0ZS9naXRsYWIucmIudGVtcGxhdGU= 100644
--- a/files/gitlab-config-template/gitlab.rb.template
+++ b/files/gitlab-config-template/gitlab.rb.template
@@ -858,7 +858,14 @@
 # gitlab_rails['redis_repository_cache_username'] = nil
 # gitlab_rails['redis_repository_cache_password'] = nil
 # gitlab_rails['redis_repository_cache_cluster_nodes'] = nil
-
+# gitlab_rails['redis_workhorse_instance'] = nil
+# gitlab_rails['redis_workhorse_sentinels'] = nil
+# gitlab_rails['redis_workhorse_sentinels_password'] = nil
+# gitlab_rails['redis_workhorse_username'] = nil
+# gitlab_rails['redis_workhorse_password'] = nil
+# gitlab_rails['redis_workhorse_cluster_nodes'] = nil
+
+# gitlab_rails['redis_workhorse_sentinel_master'] = nil
 
 # gitlab_rails['redis_yml_override'] = nil
 
diff --git a/files/gitlab-cookbooks/gitlab/attributes/default.rb b/files/gitlab-cookbooks/gitlab/attributes/default.rb
index 3eac49be9d0b76016ad458b726a85c1b296b0ca2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvYXR0cmlidXRlcy9kZWZhdWx0LnJi..221553a16e33b0f79d1a961dda043abcd1e85bf2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvYXR0cmlidXRlcy9kZWZhdWx0LnJi 100644
--- a/files/gitlab-cookbooks/gitlab/attributes/default.rb
+++ b/files/gitlab-cookbooks/gitlab/attributes/default.rb
@@ -497,6 +497,15 @@
 default['gitlab']['gitlab_rails']['redis_cluster_rate_limiting_username'] = nil
 default['gitlab']['gitlab_rails']['redis_cluster_rate_limiting_password'] = nil
 default['gitlab']['gitlab_rails']['redis_cluster_rate_limiting_cluster_nodes'] = []
+default['gitlab']['gitlab_rails']['redis_workhorse_instance'] = nil
+default['gitlab']['gitlab_rails']['redis_workhorse_sentinels'] = []
+default['gitlab']['gitlab_rails']['redis_workhorse_sentinels_password'] = nil
+default['gitlab']['gitlab_rails']['redis_workhorse_username'] = nil
+default['gitlab']['gitlab_rails']['redis_workhorse_password'] = nil
+default['gitlab']['gitlab_rails']['redis_workhorse_cluster_nodes'] = []
+
+# used by workhorse to connect to a separate external redis instead of the omnibus-gitlab redis
+default['gitlab']['gitlab_rails']['redis_workhorse_sentinel_master'] = nil
 
 default['gitlab']['gitlab_rails']['redis_yml_override'] = nil
 
diff --git a/files/gitlab-cookbooks/gitlab/libraries/redis_helper.rb b/files/gitlab-cookbooks/gitlab/libraries/redis_helper.rb
index 3eac49be9d0b76016ad458b726a85c1b296b0ca2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvbGlicmFyaWVzL3JlZGlzX2hlbHBlci5yYg==..221553a16e33b0f79d1a961dda043abcd1e85bf2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvbGlicmFyaWVzL3JlZGlzX2hlbHBlci5yYg== 100644
--- a/files/gitlab-cookbooks/gitlab/libraries/redis_helper.rb
+++ b/files/gitlab-cookbooks/gitlab/libraries/redis_helper.rb
@@ -2,7 +2,7 @@
 require 'cgi'
 
 class RedisHelper
-  REDIS_INSTANCES = %w[cache queues shared_state trace_chunks rate_limiting sessions repository_cache cluster_rate_limiting].freeze
+  REDIS_INSTANCES = %w[cache queues shared_state trace_chunks rate_limiting sessions repository_cache cluster_rate_limiting workhorse].freeze
   ALLOWED_REDIS_CLUSTER_INSTANCE = %w[cache rate_limiting cluster_rate_limiting].freeze
 
   def initialize(node)
@@ -51,6 +51,27 @@
     uri
   end
 
+  def workhorse_params
+    gitlab_rails = @node['gitlab']['gitlab_rails']
+    if gitlab_rails['redis_workhorse_instance'] || !gitlab_rails['redis_workhorse_sentinels'].empty?
+      {
+        url: gitlab_rails['redis_workhorse_instance'],
+        password: gitlab_rails['redis_workhorse_password'],
+        sentinels: redis_sentinel_urls('redis_workhorse_sentinels'),
+        sentinelMaster: gitlab_rails['redis_workhorse_sentinel_master'],
+        sentinelPassword: gitlab_rails['redis_workhorse_sentinels_password']
+      }
+    else
+      {
+        url: redis_url,
+        password: redis_params.last,
+        sentinels: redis_sentinel_urls('redis_sentinels'),
+        sentinelMaster: @node['redis']['master_name'],
+        sentinelPassword: @node['redis']['master_password']
+      }
+    end
+  end
+
   def validate_instance_shard_config(instance)
     gitlab_rails = @node['gitlab']['gitlab_rails']
 
diff --git a/files/gitlab-cookbooks/gitlab/recipes/gitlab-workhorse.rb b/files/gitlab-cookbooks/gitlab/recipes/gitlab-workhorse.rb
index 3eac49be9d0b76016ad458b726a85c1b296b0ca2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvcmVjaXBlcy9naXRsYWItd29ya2hvcnNlLnJi..221553a16e33b0f79d1a961dda043abcd1e85bf2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9naXRsYWIvcmVjaXBlcy9naXRsYWItd29ya2hvcnNlLnJi 100644
--- a/files/gitlab-cookbooks/gitlab/recipes/gitlab-workhorse.rb
+++ b/files/gitlab-cookbooks/gitlab/recipes/gitlab-workhorse.rb
@@ -88,5 +88,4 @@
 
 alt_document_root = node['gitlab']['gitlab_workhorse']['alt_document_root']
 shutdown_timeout = node['gitlab']['gitlab_workhorse']['shutdown_timeout']
-_redis_host, _redis_port, redis_password = redis_helper.redis_params
 workhorse_keywatcher = node['gitlab']['gitlab_workhorse']['workhorse_keywatcher']
@@ -92,8 +91,5 @@
 workhorse_keywatcher = node['gitlab']['gitlab_workhorse']['workhorse_keywatcher']
-redis_url = redis_helper.redis_url.to_s
-redis_sentinel_urls = redis_helper.redis_sentinel_urls('redis_sentinels')
-redis_sentinel_master = node['redis']['master_name']
-redis_sentinel_master_password = node['redis']['master_password']
+redis_params = redis_helper.workhorse_params
 config_file_path = File.join(working_dir, "config.toml")
 image_scaler_max_procs = node['gitlab']['gitlab_workhorse']['image_scaler_max_procs']
 image_scaler_max_filesize = node['gitlab']['gitlab_workhorse']['image_scaler_max_filesize']
@@ -108,8 +104,9 @@
   variables(
     alt_document_root: alt_document_root,
     workhorse_keywatcher: workhorse_keywatcher,
-    redis_url: redis_url,
-    password: redis_password,
-    sentinels: redis_sentinel_urls,
-    sentinel_master: redis_sentinel_master,
+    redis_url: redis_params[:url],
+    password: redis_params[:password],
+    sentinels: redis_params[:sentinels],
+    sentinel_master: redis_params[:sentinelMaster],
+    master_password: redis_params[:sentinelPassword],
     shutdown_timeout: shutdown_timeout,
@@ -115,5 +112,4 @@
     shutdown_timeout: shutdown_timeout,
-    master_password: redis_sentinel_master_password,
     image_scaler_max_procs: image_scaler_max_procs,
     image_scaler_max_filesize: image_scaler_max_filesize,
     trusted_cidrs_for_propagation: trusted_cidrs_for_propagation,
diff --git a/spec/chef/cookbooks/gitlab/libraries/redis_helper_spec.rb b/spec/chef/cookbooks/gitlab/libraries/redis_helper_spec.rb
index 3eac49be9d0b76016ad458b726a85c1b296b0ca2_c3BlYy9jaGVmL2Nvb2tib29rcy9naXRsYWIvbGlicmFyaWVzL3JlZGlzX2hlbHBlcl9zcGVjLnJi..221553a16e33b0f79d1a961dda043abcd1e85bf2_c3BlYy9jaGVmL2Nvb2tib29rcy9naXRsYWIvbGlicmFyaWVzL3JlZGlzX2hlbHBlcl9zcGVjLnJi 100644
--- a/spec/chef/cookbooks/gitlab/libraries/redis_helper_spec.rb
+++ b/spec/chef/cookbooks/gitlab/libraries/redis_helper_spec.rb
@@ -139,6 +139,100 @@
     end
   end
 
+  describe '#workhorse_params' do
+    let(:baseline_config_with_sentinel) do
+      {
+        gitlab_rails: {
+          redis_host: 'redis.example.com',
+          redis_port: 8888,
+          redis_password: 'mypass',
+          redis_sentinels: [
+            { 'host' => 'sentinel1.example.com', 'port' => '12345' },
+            { 'host' => 'sentinel2.example.com', 'port' => '12345' }
+          ]
+        },
+        redis: {
+          master_name: 'master_from.redis.master_name',
+          master_password: 'password_from.redis.master_password'
+        }
+      }
+    end
+
+    before { allow(Gitlab).to receive(:[]).and_call_original }
+
+    context 'without external workhorse redis' do
+      context 'when no sentinels are configured' do
+        it 'renders parameters for workhorse redis' do
+          stub_gitlab_rb(
+            gitlab_rails: {
+              redis_host: 'redis.example.com',
+              redis_port: 8888,
+              redis_password: 'mypass'
+            }
+          )
+
+          params = subject.workhorse_params
+          expect(params[:password]).to eq('mypass')
+          expect(params[:sentinels]).to eq([])
+          expect(params[:url].to_s).to eq('redis://:mypass@redis.example.com:8888/')
+        end
+      end
+
+      context 'when sentinels are configured' do
+        it 'renders parameters for workhorse redis' do
+          stub_gitlab_rb(baseline_config_with_sentinel)
+
+          params = subject.workhorse_params
+          expect(params[:password]).to eq('password_from.redis.master_password')
+          expect(params[:sentinels].map(&:to_s)).to eq(%w[redis://sentinel1.example.com:12345 redis://sentinel2.example.com:12345])
+          expect(params[:sentinelMaster]).to eq('master_from.redis.master_name')
+          expect(params[:sentinelPassword]).to eq('password_from.redis.master_password')
+          expect(params[:url].to_s).to eq("redis://:password_from.redis.master_password@master_from.redis.master_name/")
+        end
+      end
+    end
+
+    context 'with external workhorse redis' do
+      context 'when no sentinels are configured' do
+        it 'renders parameters for workhorse redis' do
+          stub_gitlab_rb(baseline_config_with_sentinel.merge({
+                                                               gitlab_rails: {
+                                                                 redis_workhorse_instance: "redis://:redis.workhorse.com:8888",
+                                                                 redis_workhorse_password: "workhorse.password"
+                                                               }
+                                                             }))
+
+          params = subject.workhorse_params
+          expect(params[:password]).to eq('workhorse.password')
+          expect(params[:sentinels]).to eq([])
+          expect(params[:url].to_s).to eq('redis://:redis.workhorse.com:8888')
+        end
+      end
+
+      context 'when sentinels are configured' do
+        it 'renders parameters for workhorse redis' do
+          stub_gitlab_rb(baseline_config_with_sentinel.merge({
+                                                               gitlab_rails: {
+                                                                 redis_workhorse_sentinels: [
+                                                                   { 'host' => 'sentinel1.workhorse.com', 'port' => '12345' },
+                                                                   { 'host' => 'sentinel2.workhorse.com', 'port' => '12345' }
+                                                                 ],
+                                                                 redis_workhorse_sentinels_password: "workhorse.password",
+                                                                 redis_workhorse_sentinel_master: "workhorse.master"
+                                                               }
+                                                             }))
+
+          params = subject.workhorse_params
+          expect(params[:password]).to be_nil
+          expect(params[:sentinels].map(&:to_s)).to eq(%w[redis://:workhorse.password@sentinel1.workhorse.com:12345 redis://:workhorse.password@sentinel2.workhorse.com:12345])
+          expect(params[:sentinelMaster]).to eq('workhorse.master')
+          expect(params[:sentinelPassword]).to eq('workhorse.password')
+          expect(params[:url]).to eq(nil)
+        end
+      end
+    end
+  end
+
   describe '#running_version' do
     let(:redis_cli_output) do
       <<~MSG
diff --git a/spec/chef/cookbooks/gitlab/recipes/gitlab-workhorse_spec.rb b/spec/chef/cookbooks/gitlab/recipes/gitlab-workhorse_spec.rb
index 3eac49be9d0b76016ad458b726a85c1b296b0ca2_c3BlYy9jaGVmL2Nvb2tib29rcy9naXRsYWIvcmVjaXBlcy9naXRsYWItd29ya2hvcnNlX3NwZWMucmI=..221553a16e33b0f79d1a961dda043abcd1e85bf2_c3BlYy9jaGVmL2Nvb2tib29rcy9naXRsYWIvcmVjaXBlcy9naXRsYWItd29ya2hvcnNlX3NwZWMucmI= 100644
--- a/spec/chef/cookbooks/gitlab/recipes/gitlab-workhorse_spec.rb
+++ b/spec/chef/cookbooks/gitlab/recipes/gitlab-workhorse_spec.rb
@@ -619,6 +619,71 @@
     end
   end
 
+  context 'with separate workhorse redis details specified' do
+    context 'with standalone redis defined' do
+      before do
+        stub_gitlab_rb(
+          gitlab_rails: {
+            redis_sentinels: [
+              { 'host' => '127.0.0.1', 'port' => 26379 },
+              { 'host' => '127.0.8.1', 'port' => 12345 }
+            ],
+            redis_workhorse_instance: "unix:/home/random/path.socket",
+            redis_workhorse_password: 'some pass'
+          },
+          redis: {
+            master_name: 'examplemaster',
+            master_password: 'examplepassword'
+          }
+        )
+      end
+
+      it 'should generate config file with the specified values' do
+        content_url = 'URL = "unix:/home/random/path.socket"'
+        content_password = 'Password = "some pass"'
+        expect(chef_run).to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(content_url)
+        expect(chef_run).to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(content_password)
+        expect(chef_run).not_to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(/Sentinel/)
+        expect(chef_run).not_to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(/SentinelMaster/)
+      end
+    end
+
+    context 'with sentinels defined' do
+      before do
+        stub_gitlab_rb(
+          gitlab_rails: {
+            redis_sentinels: [
+              { 'host' => '127.0.0.1', 'port' => 26379 },
+              { 'host' => '127.0.8.1', 'port' => 12345 }
+            ],
+            redis_sentinels_password: 'some pass',
+            redis_workhorse_sentinels: [
+              { 'host' => '127.0.0.2', 'port' => 26379 },
+              { 'host' => '127.0.8.2', 'port' => 12345 }
+            ],
+            redis_workhorse_sentinels_password: 'some workhorse pass',
+            redis_workhorse_sentinel_master: 'worhorse.master'
+          },
+          redis: {
+            master_name: 'examplemaster',
+            master_password: 'examplepassword'
+          }
+        )
+      end
+
+      it 'should generate config file with the specified values' do
+        content = 'Sentinel = ["redis://:some+workhorse+pass@127.0.0.2:26379","redis://:some+workhorse+pass@127.0.8.2:12345"]'
+        content_sentinel_master = 'SentinelMaster = "worhorse.master"'
+        content_sentinel_password = 'Password = "some workhorse pass"'
+        content_url = 'URL ='
+        expect(chef_run).to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(content)
+        expect(chef_run).to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(content_sentinel_master)
+        expect(chef_run).to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(content_sentinel_password)
+        expect(chef_run).not_to render_file("/var/opt/gitlab/gitlab-workhorse/config.toml").with_content(content_url)
+      end
+    end
+  end
+
   context 'image scaler' do
     context 'with default values' do
       it 'sets the default maximum file size' do