--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -14147,6 +14147,33 @@
   mpvio_info(mpvio->auth_info.thd->net.vio, info);
 }
 
+
+/*
+  Compare two X509_NAME_oneline() strings, ignoring the backslash OpenSSL 3
+  inserts before '/' and '+'. OpenSSL 1.1.1 emitted those characters raw, and
+  existing REQUIRE ISSUER / REQUIRE SUBJECT grants store that rendering.
+  Bidirectional: either side may be escaped. No allocation; does not mutate
+  acl_user->x509_issuer / x509_subject (const on the shared ACL object).
+*/
+static int kdba_x509_oneline_cmp(const char *a, const char *b)
+{
+  if (!a || !b)
+    return a != b;
+  for (;;)
+  {
+    if (*a == '\\' && (a[1] == '/' || a[1] == '+'))
+      a++;
+    if (*b == '\\' && (b[1] == '/' || b[1] == '+'))
+      b++;
+    if (*a != *b)
+      return (unsigned char)*a - (unsigned char)*b;
+    if (*a == '\0')
+      return 0;
+    a++;
+    b++;
+  }
+}
+
 static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user)
 {
   Vio *vio= thd->net.vio;
@@ -14232,7 +14259,7 @@
       char *ptr= X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
       DBUG_PRINT("info", ("comparing issuers: '%s' and '%s'",
                          acl_user->x509_issuer, ptr));
-      if (strcmp(acl_user->x509_issuer, ptr))
+      if (kdba_x509_oneline_cmp(acl_user->x509_issuer, ptr))
       {
         if (global_system_variables.log_warnings)
           sql_print_information("X509 issuer mismatch: should be '%s' "
@@ -14249,7 +14276,7 @@
       char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
       DBUG_PRINT("info", ("comparing subjects: '%s' and '%s'",
                          acl_user->x509_subject, ptr));
-      if (strcmp(acl_user->x509_subject, ptr))
+      if (kdba_x509_oneline_cmp(acl_user->x509_subject, ptr))
       {
         if (global_system_variables.log_warnings)
           sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
