diff --git a/ee/app/services/security/scan_result_policies/generate_policy_violation_comment_service.rb b/ee/app/services/security/scan_result_policies/generate_policy_violation_comment_service.rb
index 1ffaf420f05ed58b7110d90917ca89db8acefb37..cefce601079a6963c2ba4439edc3113a211b7d42 100644
--- a/ee/app/services/security/scan_result_policies/generate_policy_violation_comment_service.rb
+++ b/ee/app/services/security/scan_result_policies/generate_policy_violation_comment_service.rb
@@ -44,7 +44,7 @@ def exclusive_lock_key
       end
 
       def comment
-        @comment ||= PolicyViolationComment.new(existing_comment).tap do |violation_comment|
+        @comment ||= PolicyViolationComment.new(existing_comment, project).tap do |violation_comment|
           violation_comment.remove_report_type(report_type)
           violation_comment.add_report_type(report_type, requires_approval) if violated_policy
         end
diff --git a/ee/lib/security/scan_result_policies/policy_violation_comment.rb b/ee/lib/security/scan_result_policies/policy_violation_comment.rb
index fecdf43ea9e0e347b1b988b75485aa80e431c693..c6a6be4987ac3c787fa1bdec857dc50ea36557b1 100644
--- a/ee/lib/security/scan_result_policies/policy_violation_comment.rb
+++ b/ee/lib/security/scan_result_policies/policy_violation_comment.rb
@@ -3,6 +3,8 @@
 module Security
   module ScanResultPolicies
     class PolicyViolationComment
+      include Rails.application.routes.url_helpers
+
       MESSAGE_HEADER = '<!-- policy_violation_comment -->'
       VIOLATED_REPORTS_HEADER_PATTERN = /<!-- violated_reports: ([a-z_,]+)/
       OPTIONAL_APPROVALS_HEADER_PATTERN = /<!-- optional_approvals: ([a-z_,]+)/
@@ -11,11 +13,17 @@ class PolicyViolationComment
         scan_finding: 'scan_finding',
         any_merge_request: 'any_merge_request'
       }.freeze
-      MESSAGE_REQUIRES_APPROVAL = <<~TEXT.squish
+      MESSAGE_REQUIRES_APPROVAL = <<~MARKDOWN
         Security and compliance scanners enforced by your organization have completed and identified that approvals
         are required due to one or more policy violations.
         Review the policy's rules in the MR widget and assign reviewers to proceed.
-      TEXT
+
+        Several factors can lead to a violation or required approval in your merge request:
+
+        - If merge request approval policies enforced on your project include a scanner in the conditions, the scanner must be properly configured to run in both the source and target branch, the required jobs must complete, and a job artifact containing the scan results must be produced (even if empty).
+        - If any violation of a merge request approval policy's rules are found, approval is required.
+- Approvals are assumed required until all pipelines associated with the merge base commit in the target branch, and all pipelines associated with the latest commit in the source branch, are complete and it's confirmed that no policy violations have occurred.
+      MARKDOWN
 
       MESSAGE_REQUIRES_NO_APPROVAL = <<~TEXT.squish
         Security and compliance scanners enforced by your organization have completed and identified one or more
@@ -23,12 +31,13 @@ class PolicyViolationComment
         Consider including optional reviewers based on the policy rules in the MR widget.
       TEXT
 
-      attr_reader :reports, :optional_approval_reports, :existing_comment
+      attr_reader :reports, :optional_approval_reports, :existing_comment, :project
 
-      def initialize(existing_comment)
+      def initialize(existing_comment, project)
         @existing_comment = existing_comment
         @reports = Set.new
         @optional_approval_reports = Set.new
+        @project = project
 
         return unless existing_comment
 
@@ -71,20 +80,33 @@ def fixed_note_body
         'Security policy violations have been resolved.'
       end
 
+      def links_approvals_required
+        <<~MARKDOWN
+
+          [View policies enforced on your project](#{project_security_policies_url(project)}).<br>
+          [View further troubleshooting guidance](#{help_page_url('user/application_security/policies/index', anchor: 'troubleshooting-common-issues-configuring-security-policies')}).
+        MARKDOWN
+      end
+
       def body_message
         return fixed_note_body if reports.empty?
 
-        message = reports == optional_approval_reports ? MESSAGE_REQUIRES_NO_APPROVAL : MESSAGE_REQUIRES_APPROVAL
+        message, links = if reports == optional_approval_reports
+                           [MESSAGE_REQUIRES_NO_APPROVAL, '']
+                         else
+                           [MESSAGE_REQUIRES_APPROVAL, links_approvals_required]
+                         end
+
         optional_approvals_sorted_list = optional_approval_reports.sort.join(',')
         <<~MARKDOWN
           <!-- violated_reports: #{reports.sort.join(',')} -->
           #{"<!-- optional_approvals: #{optional_approvals_sorted_list} -->" if optional_approval_reports.any?}
-          | :warning: **Policy violation(s) detected**|
-          | ----------------------------------------- |
-          | #{message}                                |
+          :warning: **Policy violation(s) detected**
+
+          #{message}#{links}
 
           #{format('Learn more about [Security and Compliance policies](%{url}).',
-            url: Rails.application.routes.url_helpers.help_page_url('user/application_security/policies/index'))}
+            url: help_page_url('user/application_security/policies/index'))}
         MARKDOWN
       end
     end
diff --git a/ee/spec/lib/security/scan_result_policies/policy_violation_comment_spec.rb b/ee/spec/lib/security/scan_result_policies/policy_violation_comment_spec.rb
index bed2a1745b3e01fc6b8f07e6eb6c835f0237d1f8..a2bb194e4a34b062ae462200af67c9df42c76c64 100644
--- a/ee/spec/lib/security/scan_result_policies/policy_violation_comment_spec.rb
+++ b/ee/spec/lib/security/scan_result_policies/policy_violation_comment_spec.rb
@@ -5,7 +5,8 @@
 RSpec.describe Security::ScanResultPolicies::PolicyViolationComment, feature_category: :security_policy_management do
   using RSpec::Parameterized::TableSyntax
 
-  let(:comment) { described_class.new(existing_comment) }
+  let_it_be(:project) { create(:project) }
+  let(:comment) { described_class.new(existing_comment, project) }
 
   def build_comment(reports: [], optional_approvals: [])
     build(:note,
@@ -104,9 +105,9 @@ def build_comment(reports: [], optional_approvals: [])
   describe '#body' do
     subject { comment.body }
 
-    let_it_be(:violations_resolved) { 'Security policy violations have been resolved.' }
-    let_it_be(:violations_detected) { 'Policy violation(s) detected' }
-    let_it_be(:optional_approvals_detected) { 'Consider including optional reviewers' }
+    let_it_be(:violations_resolved) { ['Security policy violations have been resolved.'] }
+    let_it_be(:violations_detected) { ['Policy violation(s) detected', 'View policies enforced on your project'] }
+    let_it_be(:optional_approvals_detected) { ['Consider including optional reviewers'] }
 
     context 'when there is no existing comment and no reports' do
       let(:existing_comment) { nil }
@@ -133,7 +134,7 @@ def build_comment(reports: [], optional_approvals: [])
       end
 
       it { is_expected.to start_with(described_class::MESSAGE_HEADER) }
-      it { is_expected.to include(expected_body) }
+      it { is_expected.to include(*expected_body) }
     end
   end
 end