diff --git a/app/assets/javascripts/clusters/agents/index.js b/app/assets/javascripts/clusters/agents/index.js
index 2070a32426e471b49f4c99afcb8976246f719b3b..70ad63e472e7db2660b836f9c19e97999dbeece9 100644
--- a/app/assets/javascripts/clusters/agents/index.js
+++ b/app/assets/javascripts/clusters/agents/index.js
@@ -18,7 +18,7 @@ export default () => {
     emptyStateSvgPath,
     projectPath,
     kasAddress,
-    kasVersion,
+    kasInstallVersion,
     canAdminCluster,
   } = el.dataset;
 
@@ -33,7 +33,7 @@ export default () => {
       emptyStateSvgPath,
       projectPath,
       kasAddress,
-      kasVersion,
+      kasInstallVersion,
       canAdminCluster: parseBoolean(canAdminCluster),
     },
     render(createElement) {
diff --git a/app/assets/javascripts/clusters_list/components/agent_table.vue b/app/assets/javascripts/clusters_list/components/agent_table.vue
index f74555ad9e1dc0ef1aeffbdea579a87cd298d83f..ea8716c78c619171872cb623aa28421753bc1287 100644
--- a/app/assets/javascripts/clusters_list/components/agent_table.vue
+++ b/app/assets/javascripts/clusters_list/components/agent_table.vue
@@ -47,7 +47,7 @@ export default {
   configHelpLink: helpPagePath('user/clusters/agent/install/index', {
     anchor: 'create-an-agent-configuration-file',
   }),
-  inject: ['kasVersion'],
+  inject: ['kasCheckVersion'],
   props: {
     agents: {
       required: true,
@@ -177,12 +177,12 @@ export default {
       const agentVersion = this.getAgentVersionString(agent);
       let allowableAgentVersion = semverInc(agentVersion, 'minor');
 
-      const isServerPrerelease = Boolean(semverPrerelease(this.kasVersion));
+      const isServerPrerelease = Boolean(semverPrerelease(this.kasCheckVersion));
       if (isServerPrerelease) {
         allowableAgentVersion = semverInc(allowableAgentVersion, 'minor');
       }
 
-      return semverLt(allowableAgentVersion, this.kasVersion);
+      return semverLt(allowableAgentVersion, this.kasCheckVersion);
     },
 
     getVersionPopoverTitle(agent) {
@@ -290,7 +290,7 @@ export default {
 
             <p class="gl-mb-0">
               <gl-sprintf :message="$options.i18n.versionOutdatedText">
-                <template #version>{{ kasVersion }}</template>
+                <template #version>{{ kasCheckVersion }}</template>
               </gl-sprintf>
               <gl-link :href="$options.versionUpdateLink" class="gl-font-sm">
                 {{ $options.i18n.viewDocsText }}</gl-link
@@ -303,7 +303,7 @@ export default {
 
           <p v-else-if="isVersionOutdated(item)" class="gl-mb-0">
             <gl-sprintf :message="$options.i18n.versionOutdatedText">
-              <template #version>{{ kasVersion }}</template>
+              <template #version>{{ kasCheckVersion }}</template>
             </gl-sprintf>
             <gl-link :href="$options.versionUpdateLink" class="gl-font-sm">
               {{ $options.i18n.viewDocsText }}</gl-link
diff --git a/app/assets/javascripts/clusters_list/components/agent_token.vue b/app/assets/javascripts/clusters_list/components/agent_token.vue
index 5f40815bd0295b707e583f541160ed7957a9d642..84b3f9fca2a8dcfbe9e202ca6fc1609e4f50543d 100644
--- a/app/assets/javascripts/clusters_list/components/agent_token.vue
+++ b/app/assets/javascripts/clusters_list/components/agent_token.vue
@@ -21,7 +21,7 @@ export default {
     GlIcon,
     ModalCopyButton,
   },
-  inject: ['kasAddress', 'kasVersion'],
+  inject: ['kasAddress', 'kasInstallVersion'],
   props: {
     agentName: {
       required: true,
@@ -41,7 +41,7 @@ export default {
       return generateAgentRegistrationCommand({
         name: this.agentName,
         token: this.agentToken,
-        version: this.kasVersion,
+        version: this.kasInstallVersion,
         address: this.kasAddress,
       });
     },
diff --git a/app/assets/javascripts/clusters_list/index.js b/app/assets/javascripts/clusters_list/index.js
index 3ceb5ac2e8c46bb8f504efffbc1624d67ef3cd63..cee97d0562e5bdaf3bffa63cd512103383d44184 100644
--- a/app/assets/javascripts/clusters_list/index.js
+++ b/app/assets/javascripts/clusters_list/index.js
@@ -29,7 +29,8 @@ export default () => {
     clustersEmptyStateImage,
     canAddCluster,
     canAdminCluster,
-    kasVersion,
+    kasInstallVersion,
+    kasCheckVersion,
     displayClusterAgents,
     certificateBasedClustersEnabled,
   } = el.dataset;
@@ -47,7 +48,8 @@ export default () => {
       clustersEmptyStateImage,
       canAddCluster: parseBoolean(canAddCluster),
       canAdminCluster: parseBoolean(canAdminCluster),
-      kasVersion,
+      kasInstallVersion,
+      kasCheckVersion,
       displayClusterAgents: parseBoolean(displayClusterAgents),
       certificateBasedClustersEnabled: parseBoolean(certificateBasedClustersEnabled),
     },
diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb
index d58b8da25ea8ef81c7ca696076fa14d94136f42b..9371814e3701b37aaaa312ecffc030ed1fba2562 100644
--- a/app/helpers/clusters_helper.rb
+++ b/app/helpers/clusters_helper.rb
@@ -26,7 +26,8 @@ def js_clusters_list_data(clusterable)
       default_branch_name: default_branch_name(clusterable),
       project_path: clusterable_project_path(clusterable),
       kas_address: Gitlab::Kas.external_url,
-      kas_version: Gitlab::Kas.version_info
+      kas_install_version: Gitlab::Kas.install_version_info,
+      kas_check_version: Gitlab::Kas.display_version_info
     }
   end
 
diff --git a/app/helpers/projects/cluster_agents_helper.rb b/app/helpers/projects/cluster_agents_helper.rb
index 7eaf3d4bbd0f29784e2120d0f10a6f8101d12141..15ede867292ea6770865359697a13059cd77795a 100644
--- a/app/helpers/projects/cluster_agents_helper.rb
+++ b/app/helpers/projects/cluster_agents_helper.rb
@@ -9,7 +9,7 @@ def js_cluster_agent_details_data(agent_name, project)
       empty_state_svg_path: image_path('illustrations/empty-state/empty-radar-md.svg'),
       project_path: project.full_path,
       kas_address: Gitlab::Kas.external_url,
-      kas_version: Gitlab::Kas.version_info,
+      kas_install_version: Gitlab::Kas.install_version_info,
       can_admin_cluster: can?(current_user, :admin_cluster, project).to_s
     }
   end
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 7e6dd5f62a86d651033980c4ad546a8f1a01bd82..54a69ec6d293221b58b9bc0ce50f79856cb31083 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -149,7 +149,7 @@
             %p
               = _('GitLab KAS')
               %span.gl-float-right
-                = Gitlab::Kas.version
+                = Gitlab::Kas.display_version_info
 
           = render_if_exists 'admin/dashboard/geo'
 
diff --git a/lib/gitlab/kas.rb b/lib/gitlab/kas.rb
index de391c451215c990f751f7ecfad839ce2faa2563..035c0c631933beaf8ff05ab65327bb90712e3671 100644
--- a/lib/gitlab/kas.rb
+++ b/lib/gitlab/kas.rb
@@ -31,11 +31,44 @@ def ensure_secret!
       #
       # @return [String] version
       def version
-        @_version ||= Rails.root.join(VERSION_FILE).read.chomp
+        version_info.to_s
       end
 
+      # Return GitLab KAS version info
+      #
+      # @return [Gitlab::VersionInfo] version_info
       def version_info
-        Gitlab::VersionInfo.parse(version, parse_suffix: true)
+        return version_info_from_file if version_info_from_file.valid?
+
+        version_info_from_gitlab_and_file_sha
+      end
+
+      # Return GitLab KAS version info for display
+      # This is the version that is displayed on the `frontend`. This is also used to
+      # check if the version of an existing agent does not match the latest agent version.
+      # If the GITLAB_KAS_VERSION file contains a SHA, we defer instead to the Gitlab version.
+      #
+      # For further details, see: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/149794
+      #
+      # @return [Gitlab::VersionInfo] version_info
+      def display_version_info
+        return version_info_from_file if version_info_from_file.valid?
+
+        Gitlab.version_info
+      end
+
+      # Return GitLab KAS version info for installation
+      # This is the version used as the image tag when generating the command to install a Gitlab agent.
+      # If the GITLAB_KAS_VERSION file contains a SHA, we defer instead to the Gitlab version without the patch.
+      # This could mean that it might point to a Gitlab agent version that is several patches behind the latest one.
+      #
+      # Further details: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/149794
+      #
+      # @return [Gitlab::VersionInfo] version_info
+      def install_version_info
+        return version_info_from_file if version_info_from_file.valid?
+
+        Gitlab.version_info.without_patch
       end
 
       # Return GitLab KAS external_url
@@ -78,6 +111,18 @@ def enabled?
 
       private
 
+      def version_file_content
+        Rails.root.join(VERSION_FILE).read.chomp
+      end
+
+      def version_info_from_file
+        Gitlab::VersionInfo.parse(version_file_content, parse_suffix: true)
+      end
+
+      def version_info_from_gitlab_and_file_sha
+        Gitlab::VersionInfo.parse("#{Gitlab.version_info}+#{version_file_content}", parse_suffix: true)
+      end
+
       def ssl?
         URI(tunnel_url).scheme === 'https'
       end
diff --git a/spec/frontend/clusters_list/components/agent_table_spec.js b/spec/frontend/clusters_list/components/agent_table_spec.js
index e3adefd86b21415fe6a0f5f616068ac51f7f774a..d8357d1d0ef83629d07331956e096c9c00282499 100644
--- a/spec/frontend/clusters_list/components/agent_table_spec.js
+++ b/spec/frontend/clusters_list/components/agent_table_spec.js
@@ -12,7 +12,7 @@ const defaultConfigHelpUrl =
   '/help/user/clusters/agent/install/index#create-an-agent-configuration-file';
 
 const provideData = {
-  kasVersion: '14.8.0',
+  kasCheckVersion: '14.8.0',
 };
 const defaultProps = {
   agents: clusterAgents,
@@ -132,7 +132,7 @@ describe('AgentTable', () => {
     });
 
     describe.each`
-      agentMockIdx | agentVersion | kasVersion      | versionMismatch | versionOutdated | title
+      agentMockIdx | agentVersion | kasCheckVersion | versionMismatch | versionOutdated | title
       ${0}         | ${''}        | ${'14.8.0'}     | ${false}        | ${false}        | ${''}
       ${1}         | ${'14.8.0'}  | ${'14.8.0'}     | ${false}        | ${false}        | ${''}
       ${2}         | ${'14.6.0'}  | ${'14.8.0'}     | ${false}        | ${true}         | ${outdatedTitle}
@@ -144,8 +144,15 @@ describe('AgentTable', () => {
       ${8}         | ${'14.8.0'}  | ${'14.8.10'}    | ${false}        | ${false}        | ${''}
       ${9}         | ${''}        | ${'14.8.0'}     | ${false}        | ${false}        | ${''}
     `(
-      'when agent version is "$agentVersion", KAS version is "$kasVersion" and version mismatch is "$versionMismatch"',
-      ({ agentMockIdx, agentVersion, kasVersion, versionMismatch, versionOutdated, title }) => {
+      'when agent version is "$agentVersion", KAS version is "$kasCheckVersion" and version mismatch is "$versionMismatch"',
+      ({
+        agentMockIdx,
+        agentVersion,
+        kasCheckVersion,
+        versionMismatch,
+        versionOutdated,
+        title,
+      }) => {
         const currentAgent = clusterAgents[agentMockIdx];
 
         const findIcon = () => findVersionText(0).findComponent(GlIcon);
@@ -153,12 +160,12 @@ describe('AgentTable', () => {
 
         const versionWarning = versionMismatch || versionOutdated;
         const outdatedText = sprintf(I18N_AGENT_TABLE.versionOutdatedText, {
-          version: kasVersion,
+          version: kasCheckVersion,
         });
 
         beforeEach(() => {
           createWrapper({
-            provide: { kasVersion },
+            provide: { kasCheckVersion },
             propsData: { agents: [currentAgent] },
           });
         });
diff --git a/spec/frontend/clusters_list/components/agent_token_spec.js b/spec/frontend/clusters_list/components/agent_token_spec.js
index 9be3976fea2629770ee18fd9f9baf1cd557a6ea5..8bafa11b1cb414b447ffdd67751991a6574304ee 100644
--- a/spec/frontend/clusters_list/components/agent_token_spec.js
+++ b/spec/frontend/clusters_list/components/agent_token_spec.js
@@ -14,7 +14,7 @@ import CodeBlock from '~/vue_shared/components/code_block.vue';
 const kasAddress = 'kas.example.com';
 const agentName = 'my-agent';
 const agentToken = 'agent-token';
-const kasVersion = '15.0.0';
+const kasInstallVersion = '15.0.0';
 const modalId = INSTALL_AGENT_MODAL_ID;
 
 describe('InstallAgentModal', () => {
@@ -30,7 +30,7 @@ describe('InstallAgentModal', () => {
   const createWrapper = (newAgentName = agentName) => {
     const provide = {
       kasAddress,
-      kasVersion,
+      kasInstallVersion,
     };
 
     const propsData = {
@@ -83,7 +83,7 @@ describe('InstallAgentModal', () => {
         text: generateAgentRegistrationCommand({
           name: agentName,
           token: agentToken,
-          version: kasVersion,
+          version: kasInstallVersion,
           address: kasAddress,
         }),
         modalId,
@@ -99,7 +99,7 @@ describe('InstallAgentModal', () => {
       expect(findCodeBlock().props('code')).toContain(`--namespace gitlab-agent-${agentName}`);
       expect(findCodeBlock().props('code')).toContain(`--set config.token=${agentToken}`);
       expect(findCodeBlock().props('code')).toContain(`--set config.kasAddress=${kasAddress}`);
-      expect(findCodeBlock().props('code')).toContain(`--set image.tag=v${kasVersion}`);
+      expect(findCodeBlock().props('code')).toContain(`--set image.tag=v${kasInstallVersion}`);
     });
 
     it('truncates the namespace name if it exceeds the maximum length', () => {
diff --git a/spec/helpers/clusters_helper_spec.rb b/spec/helpers/clusters_helper_spec.rb
index 5b5b3a31fd726cdd2710ecb68aa0286bd0370ba7..8ec3535d531988e17532b1a4f59910c4bc54f5e8 100644
--- a/spec/helpers/clusters_helper_spec.rb
+++ b/spec/helpers/clusters_helper_spec.rb
@@ -86,8 +86,9 @@
       expect(subject[:kas_address]).to eq(Gitlab::Kas.external_url)
     end
 
-    it 'displays KAS version' do
-      expect(subject[:kas_version]).to eq(Gitlab::Kas.version_info)
+    it 'displays KAS versions' do
+      expect(subject[:kas_install_version]).to eq(Gitlab::Kas.install_version_info)
+      expect(subject[:kas_check_version]).to eq(Gitlab::Kas.display_version_info)
     end
 
     context 'user has no permissions to create a cluster' do
diff --git a/spec/helpers/projects/cluster_agents_helper_spec.rb b/spec/helpers/projects/cluster_agents_helper_spec.rb
index 4045a7f6bf784d31f89a208a8b347118c250d0eb..d878ddf77dbeab0317305c3fe8025a65e7bc12ba 100644
--- a/spec/helpers/projects/cluster_agents_helper_spec.rb
+++ b/spec/helpers/projects/cluster_agents_helper_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe Projects::ClusterAgentsHelper do
+RSpec.describe Projects::ClusterAgentsHelper, feature_category: :deployment_management do
   describe '#js_cluster_agent_details_data' do
     let_it_be(:project) { create(:project) }
     let_it_be(:current_user) { create(:user) }
@@ -33,7 +33,7 @@
         empty_state_svg_path: kind_of(String),
         can_admin_vulnerability: "true",
         kas_address: Gitlab::Kas.external_url,
-        kas_version: Gitlab::Kas.version_info,
+        kas_install_version: Gitlab::Kas.install_version_info,
         can_admin_cluster: "false"
       })
     }
diff --git a/spec/lib/gitlab/kas_spec.rb b/spec/lib/gitlab/kas_spec.rb
index 69d9ca7d4ed3364d5d4d0508f3570137018aa76e..870fde1e555e2fd0861a8e228a2b6bf5edd7bf9d 100644
--- a/spec/lib/gitlab/kas_spec.rb
+++ b/spec/lib/gitlab/kas_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe Gitlab::Kas do
+RSpec.describe Gitlab::Kas, feature_category: :deployment_management do
   let(:jwt_secret) { SecureRandom.random_bytes(described_class::SECRET_LENGTH) }
 
   before do
@@ -184,23 +184,70 @@
     end
   end
 
-  describe '.version' do
-    it 'returns gitlab_kas version config' do
-      version_file = Rails.root.join(described_class::VERSION_FILE)
+  describe 'version information' do
+    it 'has valid version_infos' do
+      expect(described_class.version_info).to be_valid
+      expect(described_class.display_version_info).to be_valid
+      expect(described_class.install_version_info).to be_valid
+    end
 
-      expect(described_class.version).to eq(version_file.read.chomp)
+    it 'has a version based on the version_info' do
+      expect(described_class.version).to eq described_class.version_info.to_s
     end
-  end
 
-  describe '.version_info' do
-    let(:version) { '15.6.0-rc1' }
+    describe 'versioning according to the KAS version file content' do
+      before do
+        kas_version_file_double = instance_double(File, read: version_file_content)
+        allow(Rails.root).to receive(:join).with(Gitlab::Kas::VERSION_FILE).and_return(kas_version_file_double)
+      end
 
-    before do
-      allow(described_class).to receive(:version).and_return(version)
-    end
+      let(:version_file_content) { 'v16.10.1' }
+
+      it 'has a version and version_infos based on the KAS version file' do
+        expected_version_string = version_file_content.sub('v', '')
+
+        expect(described_class.version).to eq expected_version_string
+        expect(described_class.version_info.to_s).to eq expected_version_string
+        expect(described_class.display_version_info.to_s).to eq expected_version_string
+        expect(described_class.install_version_info.to_s).to eq expected_version_string
+      end
+
+      context 'when the KAS version file content is a release candidate version' do
+        let(:version_file_content) { 'v16.10.1-rc42' }
 
-    it 'returns gitlab_kas version config, including suffix' do
-      expect(described_class.version_info.to_s).to eq(version)
+        it 'has a version and version_infos based on the KAS version file' do
+          expected_version_string = version_file_content.sub('v', '')
+
+          expect(described_class.version).to eq expected_version_string
+          expect(described_class.version_info.to_s).to eq expected_version_string
+          expect(described_class.display_version_info.to_s).to eq expected_version_string
+          expect(described_class.install_version_info.to_s).to eq expected_version_string
+        end
+      end
+
+      context 'when the KAS version file content is a SHA' do
+        before do
+          allow(Gitlab).to receive(:version_info).and_return(gitlab_version_info)
+        end
+
+        let(:gitlab_version_info) { Gitlab::VersionInfo.parse('16.11.2') }
+        let(:version_file_content) { '5bbaac6e3d907fba9568a2e36aa1e521f589c897' }
+
+        it 'uses the Gitlab version with the SHA as suffix' do
+          expected_kas_version = '16.11.2+5bbaac6e3d907fba9568a2e36aa1e521f589c897'
+
+          expect(described_class.version_info.to_s).to eq expected_kas_version
+          expect(described_class.version).to eq expected_kas_version
+        end
+
+        it 'uses the Gitlab version without suffix as the display_version_info' do
+          expect(described_class.display_version_info.to_s).to eq '16.11.2'
+        end
+
+        it 'uses the Gitlab version with 0 patch version as the install_version_info' do
+          expect(described_class.install_version_info.to_s).to eq '16.11.0'
+        end
+      end
     end
   end
 
diff --git a/spec/views/admin/dashboard/index.html.haml_spec.rb b/spec/views/admin/dashboard/index.html.haml_spec.rb
index 9cb4d175ffc203bc7e24ecb3d604e46d2695544f..d98f19927458b2b03961daee223c804324a555a5 100644
--- a/spec/views/admin/dashboard/index.html.haml_spec.rb
+++ b/spec/views/admin/dashboard/index.html.haml_spec.rb
@@ -72,20 +72,19 @@
     end
   end
 
-  describe 'GitLab KAS' do
+  describe 'GitLab KAS', feature_category: :deployment_management do
     before do
       allow(Gitlab::Kas).to receive(:enabled?).and_return(enabled)
-      allow(Gitlab::Kas).to receive(:version).and_return('kas-1.2.3')
     end
 
     context 'KAS enabled' do
       let(:enabled) { true }
+      let(:expected_kas_version) { Gitlab::Kas.display_version_info }
 
       it 'includes KAS version' do
         render
 
-        expect(rendered).to have_content('GitLab KAS')
-        expect(rendered).to have_content('kas-1.2.3')
+        expect(rendered).to have_content("GitLab KAS #{expected_kas_version}")
       end
     end
 
@@ -96,7 +95,6 @@
         render
 
         expect(rendered).not_to have_content('GitLab KAS')
-        expect(rendered).not_to have_content('kas-1.2.3')
       end
     end
   end