diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h
index 464ff1cdc34e5aeb0ac6d4b72dfa83603049f703..a0e7cb6bf59a5655a842ab9d541dab217cfe7b92 100644
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -318,6 +318,16 @@ int ast_xml_escape(const char *string, char *outbuf, size_t buflen);
  */
 char *ast_escape_quoted(const char *string, char *outbuf, int buflen);
 
+/*!
+ * \brief Escape semicolons found in a string.
+ *
+ * \param string string to be escaped
+ * \param outbuf resulting escaped string
+ * \param buflen size of output buffer
+ * \return a pointer to the escaped string
+ */
+char *ast_escape_semicolons(const char *string, char *outbuf, int buflen);
+
 /*!
  * \brief Unescape quotes in a string
  *
diff --git a/main/config.c b/main/config.c
index 23de2c8babf72fb33ec834f9b565bca312a8f843..95f0b696e73698501765add28d3a717061bfa991 100644
--- a/main/config.c
+++ b/main/config.c
@@ -2513,6 +2513,7 @@ int ast_config_text_file_save(const char *configfile, const struct ast_config *c
 			while (var) {
 				struct ast_category_template_instance *x;
 				int found = 0;
+
 				AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
 					struct ast_variable *v;
 					for (v = x->inst->root; v; v = v->next) {
@@ -2558,10 +2559,22 @@ int ast_config_text_file_save(const char *configfile, const struct ast_config *c
 					if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
 						fprintf(f,"%s", cmt->cmt);
 				}
-				if (var->sameline)
-					fprintf(f, "%s %s %s  %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
-				else
-					fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
+
+				{ /* Block for 'escaped' scope */
+					int escaped_len = 2 * strlen(var->value) + 1;
+					char escaped[escaped_len];
+
+					ast_escape_semicolons(var->value, escaped, escaped_len);
+
+					if (var->sameline) {
+						fprintf(f, "%s %s %s  %s", var->name, (var->object ? "=>" : "="),
+							escaped, var->sameline->cmt);
+					} else {
+						fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="),
+							escaped);
+					}
+				}
+
 				for (cmt = var->trailing; cmt; cmt=cmt->next) {
 					if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
 						fprintf(f,"%s", cmt->cmt);
diff --git a/main/utils.c b/main/utils.c
index 40818c37addf1bcc5e805130bd777e688f5f89eb..3a095ca7b85838d0b4e4da3d6675f06ba16a9361 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -484,6 +484,37 @@ char *ast_escape_quoted(const char *string, char *outbuf, int buflen)
 	return outbuf;
 }
 
+char *ast_escape_semicolons(const char *string, char *outbuf, int buflen)
+{
+	const char *ptr = string;
+	char *out = outbuf;
+
+	if (string == NULL || outbuf == NULL) {
+		ast_assert(string != NULL && outbuf != NULL);
+		return NULL;
+	}
+
+	while (*ptr && out - outbuf < buflen - 1) {
+		if (*ptr == ';') {
+			if (out - outbuf >= buflen - 2) {
+				break;
+			}
+			strcpy(out, "\\;");
+			out += 2;
+		} else {
+			*out = *ptr;
+			out++;
+		}
+		ptr++;
+	}
+
+	if (buflen) {
+		*out = '\0';
+	}
+
+	return outbuf;
+}
+
 void ast_unescape_quoted(char *quote_str)
 {
 	int esc_pos;
diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c
index e76f6e892bff43b3a2dd014fa39aef6a65a9435f..a42ea47fd039c18e0bba5e2298271305c7e195d7 100644
--- a/pbx/pbx_config.c
+++ b/pbx/pbx_config.c
@@ -890,7 +890,11 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a
 	if ((v = ast_variable_browse(cfg, "globals"))) {
 		fprintf(output, "[globals]\n");
 		while(v) {
-			fprintf(output, "%s => %s\n", v->name, v->value);
+			int escaped_len = 2 * strlen(v->value) + 1;
+			char escaped[escaped_len];
+
+			ast_escape_semicolons(v->value, escaped, escaped_len);
+			fprintf(output, "%s => %s\n", v->name, escaped);
 			v = v->next;
 		}
 		fprintf(output, "\n");
@@ -951,20 +955,33 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a
 					const char *sep, *cid;
 					const char *el = ast_get_extension_label(p);
 					char label[128] = "";
- 
+					char *appdata = ast_get_extension_app_data(p);
+					char *escaped;
+
 					if (ast_get_extension_matchcid(p)) {
 						sep = "/";
 						cid = ast_get_extension_cidmatch(p);
-					} else
+					} else {
 						sep = cid = "";
-				
-					if (el && (snprintf(label, sizeof(label), "(%s)", el) != (strlen(el) + 2)))
+					}
+
+					if (el && (snprintf(label, sizeof(label), "(%s)", el) != (strlen(el) + 2))) {
 						incomplete = 1;	/* error encountered or label > 125 chars */
-					
+					}
+
+					if (!ast_strlen_zero(appdata)) {
+						int escaped_len = 2 * strlen(appdata) + 1;
+						char escaped[escaped_len];
+
+						ast_escape_semicolons(appdata, escaped, escaped_len);
+					} else {
+						escaped = "";
+					}
+
 					fprintf(output, "exten => %s%s%s,%d%s,%s(%s)\n",
 					    ast_get_extension_name(p), (ast_strlen_zero(sep) ? "" : sep), (ast_strlen_zero(cid) ? "" : cid),
 					    ast_get_extension_priority(p), label,
-					    ast_get_extension_app(p), (ast_strlen_zero(ast_get_extension_app_data(p)) ? "" : (const char *)ast_get_extension_app_data(p)));
+					    ast_get_extension_app(p), escaped);
 				}
 			}
 		}
diff --git a/tests/test_strings.c b/tests/test_strings.c
index 127ee789d8e397147ec4ff8e29c7486f2cfbd2f6..05cc8df845ad9b3d78d4b90f263b232753a04e69 100644
--- a/tests/test_strings.c
+++ b/tests/test_strings.c
@@ -387,6 +387,74 @@ AST_TEST_DEFINE(strsep_test)
 	return AST_TEST_PASS;
 }
 
+static int test_semi(char *string1, char *string2, int test_len)
+{
+	char *test2 = NULL;
+	if (test_len >= 0) {
+		test2 = ast_alloca(test_len);
+		*test2 = '\0';
+	}
+	ast_escape_semicolons(string1, test2, test_len);
+	if (test2 != NULL && strcmp(string2, test2) == 0) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+AST_TEST_DEFINE(escape_semicolons_test)
+{
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "escape_semicolons";
+		info->category = "/main/strings/";
+		info->summary = "Test ast_escape_semicolons";
+		info->description = "Test ast_escape_semicolons";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+
+	ast_test_validate(test, test_semi("this is a ;test", "this is a \\;test", 18));
+	ast_test_validate(test, test_semi(";", "\\;", 3));
+
+	/* The following tests should return empty because there's not enough room to output
+	 * an escaped ; or even a single character.
+	 */
+	ast_test_validate(test, test_semi(";", "", 0));
+	ast_test_validate(test, test_semi(";", "", 1));
+	ast_test_validate(test, test_semi(";", "", 2));
+	ast_test_validate(test, test_semi("x", "", 0));
+	ast_test_validate(test, test_semi("x", "", 1));
+
+	/* At least some output should be produced now. */
+	ast_test_validate(test, test_semi("xx;xx", "x", 2));
+	ast_test_validate(test, test_semi("xx;xx", "xx", 3));
+
+	/* There's still not enough room to output \; so
+	 * don't even print the \
+	 */
+	ast_test_validate(test, test_semi("xx;xx", "xx", 4));
+
+	ast_test_validate(test, test_semi("xx;xx", "xx\\;", 5));
+	ast_test_validate(test, test_semi("xx;xx", "xx\\;x", 6));
+	ast_test_validate(test, test_semi("xx;xx", "xx\\;xx", 7));
+	ast_test_validate(test, test_semi("xx;xx", "xx\\;xx", 8));
+
+	/* Random stuff */
+	ast_test_validate(test, test_semi("xx;xx;this is a test", "xx\\;xx\\;this is a test", 32));
+	ast_test_validate(test, test_semi(";;;;;", "\\;\\;\\;\\;\\;", 32));
+	ast_test_validate(test, test_semi(";;;;;", "\\;\\;\\;\\;", 10));
+	ast_test_validate(test, test_semi(";;;;;", "\\;\\;\\;\\;\\;", 11));
+	ast_test_validate(test, test_semi(";;\\;;;", "\\;\\;\\\\;\\;\\;", 32));
+
+	ast_test_status_update(test, "This test should produce 2 'ast_escape_semicolons: FRACK!, Failed assertion' messages.\n");
+	ast_test_validate(test, !test_semi(NULL, "xx\\;xx", 8));
+	ast_test_validate(test, !test_semi("xx;xx", "xx\\;xx", -1));
+
+	return AST_TEST_PASS;
+}
 
 static int unload_module(void)
 {
@@ -394,6 +462,7 @@ static int unload_module(void)
 	AST_TEST_UNREGISTER(begins_with_test);
 	AST_TEST_UNREGISTER(ends_with_test);
 	AST_TEST_UNREGISTER(strsep_test);
+	AST_TEST_UNREGISTER(escape_semicolons_test);
 	return 0;
 }
 
@@ -403,6 +472,7 @@ static int load_module(void)
 	AST_TEST_REGISTER(begins_with_test);
 	AST_TEST_REGISTER(ends_with_test);
 	AST_TEST_REGISTER(strsep_test);
+	AST_TEST_REGISTER(escape_semicolons_test);
 	return AST_MODULE_LOAD_SUCCESS;
 }