diff --git a/apps/app_queue.c b/apps/app_queue.c
index 13577cc68c314a72055af68d8cc7281bddbeda15..963ac24a369d9b9787fbb89b755abc86f36fc2c4 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -1014,8 +1014,6 @@ static char *app_ql = "QueueLog" ;
 
 /*! \brief Persistent Members astdb family */
 static const char * const pm_family = "Queue/PersistentMembers";
-/* The maximum length of each persistent member queue database entry */
-#define PM_MAX_LEN 8192
 
 /*! \brief queues.conf [general] option */
 static int queue_persistent_members = 0;
@@ -5815,17 +5813,19 @@ static struct member *interface_exists(struct call_queue *q, const char *interfa
 static void dump_queue_members(struct call_queue *pm_queue)
 {
 	struct member *cur_member;
-	char value[PM_MAX_LEN];
-	int value_len = 0;
-	int res;
+	struct ast_str *value;
 	struct ao2_iterator mem_iter;
 
-	memset(value, 0, sizeof(value));
-
 	if (!pm_queue) {
 		return;
 	}
 
+	/* 4K is a reasonable default for most applications, but we grow to
+	 * accommodate more if necessary. */
+	if (!(value = ast_str_create(4096))) {
+		return;
+	}
+
 	mem_iter = ao2_iterator_init(pm_queue->members, 0);
 	while ((cur_member = ao2_iterator_next(&mem_iter))) {
 		if (!cur_member->dynamic) {
@@ -5833,26 +5833,28 @@ static void dump_queue_members(struct call_queue *pm_queue)
 			continue;
 		}
 
-		res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
-			value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
+		ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s",
+			ast_str_strlen(value) ? "|" : "",
+			cur_member->interface,
+			cur_member->penalty,
+			cur_member->paused,
+			cur_member->membername,
+			cur_member->state_interface);
 
 		ao2_ref(cur_member, -1);
-
-		if (res != strlen(value + value_len)) {
-			ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
-			break;
-		}
-		value_len += res;
 	}
 	ao2_iterator_destroy(&mem_iter);
-	
-	if (value_len && !cur_member) {
-		if (ast_db_put(pm_family, pm_queue->name, value))
-		ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
+
+	if (ast_str_strlen(value) && !cur_member) {
+		if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
+			ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
+		}
 	} else {
 		/* Delete the entry if the queue is empty or there is an error */
 		ast_db_del(pm_family, pm_queue->name);
 	}
+
+	ast_free(value);
 }
 
 /*! \brief Remove member from queue 
@@ -6356,7 +6358,7 @@ static void reload_queue_members(void)
 	struct ast_db_entry *db_tree;
 	struct ast_db_entry *entry;
 	struct call_queue *cur_queue;
-	char queue_data[PM_MAX_LEN];
+	char *queue_data;
 
 	/* Each key in 'pm_family' is the name of a queue */
 	db_tree = ast_db_gettree(pm_family, NULL);
@@ -6383,7 +6385,7 @@ static void reload_queue_members(void)
 			continue;
 		}
 
-		if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) {
+		if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
 			queue_t_unref(cur_queue, "Expire reload reference");
 			continue;
 		}
@@ -6428,6 +6430,7 @@ static void reload_queue_members(void)
 			}
 		}
 		queue_t_unref(cur_queue, "Expire reload reference");
+		ast_free(queue_data);
 	}
 
 	if (db_tree) {
diff --git a/include/asterisk/astdb.h b/include/asterisk/astdb.h
index cfbebbc30140acb230b8d22f5058af113e595189..e27a6515da488a9554db28443dc50eefd809967e 100644
--- a/include/asterisk/astdb.h
+++ b/include/asterisk/astdb.h
@@ -36,6 +36,17 @@ struct ast_db_entry {
 /*!\brief Get key value specified by family/key */
 int ast_db_get(const char *family, const char *key, char *out, int outlen);
 
+/*!\brief Get key value specified by family/key as a heap allocated string.
+ *
+ * Given a \a family and \a key, sets \a out to a pointer to a heap
+ * allocated string.  In the event of an error, \a out will be set to
+ * NULL.  The string must be freed by calling ast_free().
+ *
+ * \retval -1 An error occurred
+ * \retval 0 Success
+ */
+int ast_db_get_allocated(const char *family, const char *key, char **out);
+
 /*!\brief Store value addressed by family/key */
 int ast_db_put(const char *family, const char *key, const char *value);
 
diff --git a/main/db.c b/main/db.c
index 32af90568909f328c9b5c9881eaf4141e6a6b882..05ae26cc9b8b8bde5b76613776f2bbc7d72de2a1 100644
--- a/main/db.c
+++ b/main/db.c
@@ -307,7 +307,21 @@ int ast_db_put(const char *family, const char *key, const char *value)
 	return res;
 }
 
-int ast_db_get(const char *family, const char *key, char *value, int valuelen)
+/*!
+ * \internal
+ * \brief Get key value specified by family/key.
+ *
+ * Gets the value associated with the specified \a family and \a key, and
+ * stores it, either into the fixed sized buffer specified by \a buffer
+ * and \a bufferlen, or as a heap allocated string if \a bufferlen is -1.
+ *
+ * \note If \a bufferlen is -1, \a buffer points to heap allocated memory
+ *       and must be freed by calling ast_free().
+ *
+ * \retval -1 An error occurred
+ * \retval 0 Success
+ */
+static int db_get_common(const char *family, const char *key, char **buffer, int bufferlen)
 {
 	const unsigned char *result;
 	char fullkey[MAX_DB_FIELD];
@@ -332,7 +346,13 @@ int ast_db_get(const char *family, const char *key, char *value, int valuelen)
 		ast_log(LOG_WARNING, "Couldn't get value\n");
 		res = -1;
 	} else {
-		ast_copy_string(value, (const char *) result, valuelen);
+		const char *value = (const char *) result;
+
+		if (bufferlen == -1) {
+			*buffer = ast_strdup(value);
+		} else {
+			ast_copy_string(*buffer, value, bufferlen);
+		}
 	}
 	sqlite3_reset(get_stmt);
 	ast_mutex_unlock(&dblock);
@@ -340,6 +360,23 @@ int ast_db_get(const char *family, const char *key, char *value, int valuelen)
 	return res;
 }
 
+int ast_db_get(const char *family, const char *key, char *value, int valuelen)
+{
+	ast_assert(value != NULL);
+
+	/* Make sure we initialize */
+	value[0] = 0;
+
+	return db_get_common(family, key, &value, valuelen);
+}
+
+int ast_db_get_allocated(const char *family, const char *key, char **out)
+{
+	*out = NULL;
+
+	return db_get_common(family, key, out, -1);
+}
+
 int ast_db_del(const char *family, const char *key)
 {
 	char fullkey[MAX_DB_FIELD];
diff --git a/tests/test_db.c b/tests/test_db.c
index 1bd69f0c1c485401b3ec9933ecc6c8daada35d49..9e1b5cb606a19e1ec2632f3bbed76e8eb5ecf555 100644
--- a/tests/test_db.c
+++ b/tests/test_db.c
@@ -232,11 +232,70 @@ AST_TEST_DEFINE(perftest)
 
 	return res;
 }
+
+AST_TEST_DEFINE(put_get_long)
+{
+	int res = AST_TEST_PASS;
+	struct ast_str *s;
+	int i, j;
+
+#define STR_FILL_32 "abcdefghijklmnopqrstuvwxyz123456"
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "put_get_long";
+		info->category = "/main/astdb/";
+		info->summary = "ast_db_(put|get_allocated) unit test";
+		info->description =
+			"Ensures that the ast_db_put and ast_db_get_allocated functions work";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(s = ast_str_create(4096))) {
+		return AST_TEST_FAIL;
+	}
+
+	for (i = 1024; i <= 1024 * 1024 * 8; i *= 2) {
+		char *out = NULL;
+
+		ast_str_reset(s);
+
+		for (j = 0; j < i; j += sizeof(STR_FILL_32) - 1) {
+			ast_str_append(&s, 0, "%s", STR_FILL_32);
+		}
+
+		if (ast_db_put("astdbtest", "long", ast_str_buffer(s))) {
+			ast_test_status_update(test, "Failed to put value of %zu bytes\n", ast_str_strlen(s));
+			res = AST_TEST_FAIL;
+		} else if (ast_db_get_allocated("astdbtest", "long", &out)) {
+			ast_test_status_update(test, "Failed to get value of %zu bytes\n", ast_str_strlen(s));
+			res = AST_TEST_FAIL;
+		} else if (strcmp(ast_str_buffer(s), out)) {
+			ast_test_status_update(test, "Failed to match value of %zu bytes\n", ast_str_strlen(s));
+			res = AST_TEST_FAIL;
+		} else if (ast_db_del("astdbtest", "long")) {
+			ast_test_status_update(test, "Failed to delete astdbtest/long\n");
+			res = AST_TEST_FAIL;
+		}
+
+		if (out) {
+			ast_free(out);
+		}
+	}
+
+	ast_free(s);
+
+	return res;
+}
+
 static int unload_module(void)
 {
 	AST_TEST_UNREGISTER(put_get_del);
 	AST_TEST_UNREGISTER(gettree_deltree);
 	AST_TEST_UNREGISTER(perftest);
+	AST_TEST_UNREGISTER(put_get_long);
 	return 0;
 }
 
@@ -245,6 +304,7 @@ static int load_module(void)
 	AST_TEST_REGISTER(put_get_del);
 	AST_TEST_REGISTER(gettree_deltree);
 	AST_TEST_REGISTER(perftest);
+	AST_TEST_REGISTER(put_get_long);
 	return AST_MODULE_LOAD_SUCCESS;
 }