diff --git a/doc/UPGRADE-staging/manager_amxml_attribute_fix.txt b/doc/UPGRADE-staging/manager_amxml_attribute_fix.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4b15ee92ec267da9258915574bda7ecd209c39c1
--- /dev/null
+++ b/doc/UPGRADE-staging/manager_amxml_attribute_fix.txt
@@ -0,0 +1,8 @@
+Subject: AMI
+
+The XML Manager Event Interface (amxml) now generates attribute names
+that are compliant with the XML 1.1 specification. Previously, an
+attribute name that started with a digit would be rendered as-is, even
+though attribute names must not begin with a digit. We now prefix
+attribute names that start with a digit with an underscore ('_') to
+prevent XML validation failures.
diff --git a/main/manager.c b/main/manager.c
index 8307421b2e9c3b0ff9daeccb180f4c3de4c94bc3..129ef38ba18c0d3e8d35fe52de15d4258d9875b4 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -7639,6 +7639,7 @@ static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
 	/* store in a local buffer to avoid calling ast_str_append too often */
 	char buf[256];
 	char *dst = buf;
+	const char *save = src;
 	int space = sizeof(buf);
 	/* repeat until done and nothing to flush */
 	for ( ; *src || dst != buf ; src++) {
@@ -7652,10 +7653,19 @@ static void xml_copy_escape(struct ast_str **out, const char *src, int mode)
 			}
 		}
 
-		if ( (mode & 2) && !isalnum(*src)) {
-			*dst++ = '_';
-			space--;
-			continue;
+		if (mode & 2) {
+			if (save == src && isdigit(*src)) {
+				/* The first character of an XML attribute cannot be a digit */
+				*dst++ = '_';
+				*dst++ = *src;
+				space -= 2;
+				continue;
+			} else if (!isalnum(*src)) {
+				/* Replace non-alphanumeric with an underscore */
+				*dst++ = '_';
+				space--;
+				continue;
+			}
 		}
 		switch (*src) {
 		case '<':