diff --git a/addons/res_config_mysql.c b/addons/res_config_mysql.c
index bf38a4e69b6ef9c79cdd1cd2e270cccc969f434d..f2ef949fc0cc07f89be0f637cb8f62844da1d36d 100644
--- a/addons/res_config_mysql.c
+++ b/addons/res_config_mysql.c
@@ -303,6 +303,11 @@ static char *decode_chunk(char *chunk)
 	return orig;
 }
 
+#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE"))
+
+/* MySQL requires us to escape the escape... yo dawg */
+static char *ESCAPE_CLAUSE = " ESCAPE '\\\\'";
+
 static struct ast_variable *realtime_mysql(const char *database, const char *table, const struct ast_variable *rt_fields)
 {
 	struct mysql_conn *dbh;
@@ -315,6 +320,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
 	char *stringp;
 	char *chunk;
 	char *op;
+	char *escape = "";
 	const struct ast_variable *field = rt_fields;
 	struct ast_variable *var=NULL, *prev=NULL;
 
@@ -345,20 +351,29 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	if (!strchr(field->name, ' ')) 
-		op = " ="; 
-	else 
+	if (!strchr(field->name, ' ')) {
+		op = " =";
+	} else {
 		op = "";
+		if (IS_SQL_LIKE_CLAUSE(field->name)) {
+			escape = ESCAPE_CLAUSE;
+		}
+	}
 
 	ESCAPE_STRING(buf, field->value);
-	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf));
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(buf), escape);
 	while ((field = field->next)) {
-		if (!strchr(field->name, ' ')) 
-			op = " ="; 
-		else
+		escape = "";
+		if (!strchr(field->name, ' ')) {
+			op = " =";
+		} else {
 			op = "";
+			if (IS_SQL_LIKE_CLAUSE(field->name)) {
+				escape = ESCAPE_CLAUSE;
+			}
+		}
 		ESCAPE_STRING(buf, field->value);
-		ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf));
+		ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(buf), escape);
 	}
 
 	ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", ast_str_buffer(sql));
@@ -416,6 +431,7 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
 	char *stringp;
 	char *chunk;
 	char *op;
+	char *escape = "";
 	const struct ast_variable *field = rt_fields;
 	struct ast_variable *var = NULL;
 	struct ast_config *cfg = NULL;
@@ -462,17 +478,29 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	if (!strchr(field->name, ' '))
+	if (!strchr(field->name, ' ')) {
 		op = " =";
-	else
+	} else {
 		op = "";
+		if (IS_SQL_LIKE_CLAUSE(field->name)) {
+			escape = ESCAPE_CLAUSE;
+		}
+	}
 
 	ESCAPE_STRING(buf, field->value);
-	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf));
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(buf), escape);
 	while ((field = field->next)) {
-		if (!strchr(field->name, ' ')) op = " ="; else op = "";
+		escape = "";
+		if (!strchr(field->name, ' ')) {
+			op = " =";
+		} else {
+			op = "";
+			if (IS_SQL_LIKE_CLAUSE(field->name)) {
+				escape = ESCAPE_CLAUSE;
+			}
+		}
 		ESCAPE_STRING(buf, field->value);
-		ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf));
+		ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(buf), escape);
 	}
 
 	if (initfield) {
diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c
index 25a482705ae156745799369d4938268f9ab02f01..f0859617dea216c1b578c1f5d75f887fea36198a 100644
--- a/res/res_config_pgsql.c
+++ b/res/res_config_pgsql.c
@@ -382,6 +382,9 @@ static struct columns *find_column(struct tables *t, const char *colname)
 	return NULL;
 }
 
+#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE"))
+static char *ESCAPE_CLAUSE = " ESCAPE '\\'";
+
 static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, const struct ast_variable *fields)
 {
 	RAII_VAR(PGresult *, result, NULL, PQclear);
@@ -391,6 +394,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 	char *stringp;
 	char *chunk;
 	char *op;
+	char *escape = "";
 	const struct ast_variable *field = fields;
 	struct ast_variable *var = NULL, *prev = NULL;
 
@@ -418,7 +422,14 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
-	op = strchr(field->name, ' ') ? "" : " =";
+	if (!strchr(field->name, ' ')) {
+		op = " =";
+	} else {
+		op = "";
+		if (IS_SQL_LIKE_CLAUSE(field->name)) {
+			escape = ESCAPE_CLAUSE;
+		}
+	}
 
 	ESCAPE_STRING(escapebuf, field->value);
 	if (pgresult) {
@@ -426,12 +437,17 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 		return NULL;
 	}
 
-	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, field->name, op, ast_str_buffer(escapebuf));
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", tablename, field->name, op, ast_str_buffer(escapebuf), escape);
 	while ((field = field->next)) {
-		if (!strchr(field->name, ' '))
+		escape = "";
+		if (!strchr(field->name, ' ')) {
 			op = " =";
-		else
+		} else {
 			op = "";
+			if (IS_SQL_LIKE_CLAUSE(field->name)) {
+				escape = ESCAPE_CLAUSE;
+			}
+		}
 
 		ESCAPE_STRING(escapebuf, field->value);
 		if (pgresult) {
@@ -439,7 +455,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
 			return NULL;
 		}
 
-		ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf));
+		ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(escapebuf), escape);
 	}
 
 	/* We now have our complete statement; Lets connect to the server and execute it. */
@@ -505,6 +521,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 	char *stringp;
 	char *chunk;
 	char *op;
+	char *escape = "";
 	struct ast_variable *var = NULL;
 	struct ast_config *cfg = NULL;
 	struct ast_category *cat = NULL;
@@ -543,10 +560,15 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 	/* Create the first part of the query using the first parameter/value pairs we just extracted
 	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
 
-	if (!strchr(field->name, ' '))
+	if (!strchr(field->name, ' ')) {
 		op = " =";
-	else
+		escape = "";
+	} else {
 		op = "";
+		if (IS_SQL_LIKE_CLAUSE(field->name)) {
+			escape = ESCAPE_CLAUSE;
+		}
+	}
 
 	ESCAPE_STRING(escapebuf, field->value);
 	if (pgresult) {
@@ -555,12 +577,18 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 		return NULL;
 	}
 
-	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(escapebuf));
+	ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'%s", table, field->name, op, ast_str_buffer(escapebuf), escape);
 	while ((field = field->next)) {
-		if (!strchr(field->name, ' '))
+		escape = "";
+		if (!strchr(field->name, ' ')) {
 			op = " =";
-		else
+			escape = "";
+		} else {
 			op = "";
+			if (IS_SQL_LIKE_CLAUSE(field->name)) {
+				escape = ESCAPE_CLAUSE;
+			}
+		}
 
 		ESCAPE_STRING(escapebuf, field->value);
 		if (pgresult) {
@@ -569,7 +597,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
 			return NULL;
 		}
 
-		ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf));
+		ast_str_append(&sql, 0, " AND %s%s '%s'%s", field->name, op, ast_str_buffer(escapebuf), escape);
 	}
 
 	if (initfield) {
diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c
index b5c70ec2da4d56954888beaf6dbabfcfc376a821..bb3f78e5f25aec8d83cd32e847aa1d5a123e73c6 100644
--- a/res/res_config_sqlite3.c
+++ b/res/res_config_sqlite3.c
@@ -58,6 +58,8 @@
 /*** DOCUMENTATION
  ***/
 
+static int has_explicit_like_escaping;
+
 static struct ast_config *realtime_sqlite3_load(const char *database, const char *table, const char *configfile, struct ast_config *config, struct ast_flags flags, const char *suggested_include_file, const char *who_asked);
 static struct ast_variable *realtime_sqlite3(const char *database, const char *table, const struct ast_variable *fields);
 static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, const struct ast_variable *fields);
@@ -658,6 +660,8 @@ static struct ast_config *realtime_sqlite3_load(const char *database, const char
 	return config;
 }
 
+#define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE"))
+
 /*! \brief Helper function for single and multi-row realtime load functions */
 static int realtime_sqlite3_helper(const char *database, const char *table, const struct ast_variable *fields, int is_multi, void *arg)
 {
@@ -683,6 +687,15 @@ static int realtime_sqlite3_helper(const char *database, const char *table, cons
 			ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(field->name),
 					sqlite3_escape_value(field->value));
 		}
+
+		if (has_explicit_like_escaping && IS_SQL_LIKE_CLAUSE(field->name)) {
+			/*
+			 * The realtime framework is going to pre-escape these
+			 * for us with a backslash. We just need to make sure
+			 * to tell SQLite about it
+			 */
+			ast_str_append(&sql, 0, " ESCAPE '\\'");
+		}
 	}
 
 	if (!is_multi) {
@@ -1182,6 +1195,29 @@ static int unload_module(void)
 	return 0;
 }
 
+static void discover_sqlite3_caps(void)
+{
+	/*
+	 * So we cheat a little bit here. SQLite3 added support for the
+	 * 'ESCAPE' keyword in 3.1.0. They added SQLITE_VERSION_NUMBER
+	 * in 3.1.2. So if we run into 3.1.0 or 3.1.1 in the wild, we
+	 * just treat it like < 3.1.0.
+	 *
+	 * For reference: 3.1.0, 3.1.1, and 3.1.2 were all released
+	 * within 30 days of each other in Jan/Feb 2005, so I don't
+	 * imagine we'll be finding something pre-3.1.2 that often in
+	 * practice.
+	 */
+#if defined(SQLITE_VERSION_NUMBER)
+	has_explicit_like_escaping = 1;
+#else
+	has_explicit_like_escaping = 0;
+#endif
+
+	ast_debug(3, "SQLite3 has 'LIKE ... ESCAPE ...' support? %s\n",
+			has_explicit_like_escaping ? "Yes" : "No");
+}
+
 /*!
  * \brief Load the module
  *
@@ -1194,6 +1230,8 @@ static int unload_module(void)
  */
 static int load_module(void)
 {
+	discover_sqlite3_caps();
+
 	if (!((databases = ao2_container_alloc(DB_BUCKETS, db_hash_fn, db_cmp_fn)))) {
 		return AST_MODULE_LOAD_FAILURE;
 	}