diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index 985933e2dff9461c1d0e93d2359f5de7f9db1394..efd2bd9397c9296b371832f22b5767fdf862effd 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -122,25 +122,28 @@ static int registrar_find_contact(void *obj, void *arg, int flags)
 {
 	struct ast_sip_contact *contact = obj;
 	const struct registrar_contact_details *details = arg;
-	pjsip_uri *contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
+	pjsip_uri *contact_uri;
+
+	if (ast_tvzero(contact->expiration_time)) {
+		return 0;
+	}
+
+	contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
 
 	return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH : 0;
 }
 
 /*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
-static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted)
+static int registrar_validate_contacts(const pjsip_rx_data *rdata, pj_pool_t *pool, struct ao2_container *contacts,
+	struct ast_sip_aor *aor, int permanent, int *added, int *updated, int *deleted)
 {
 	pjsip_contact_hdr *previous = NULL;
 	pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
 	struct registrar_contact_details details = {
-		.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256),
+		.pool = pool,
 	};
 
-	if (!details.pool) {
-		return -1;
-	}
-
-	while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
+	for (; (contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next)); pj_pool_reset(pool)) {
 		int expiration = registrar_get_expiration(aor, contact, rdata);
 		struct ast_sip_contact *existing;
 		char contact_uri[pjsip_max_url_size];
@@ -148,16 +151,14 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co
 		if (contact->star) {
 			/* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
 			if (expiration != 0 || previous) {
-				pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
 				return -1;
 			}
 			/* Count all contacts to delete */
-			*deleted = ao2_container_count(contacts);
+			*deleted = ao2_container_count(contacts) - permanent;
 			previous = contact;
 			continue;
 		} else if (previous && previous->star) {
 			/* If there is a previous contact and it is a '*' this is a deal breaker */
-			pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
 			return -1;
 		}
 		previous = contact;
@@ -171,13 +172,11 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co
 		/* pjsip_uri_print returns -1 if there's not enough room in the buffer */
 		if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) {
 			/* If the total length of the uri is greater than pjproject can handle, go no further */
-			pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
 			return -1;
 		}
 
 		if (details.uri->host.slen >= pj_max_hostname) {
 			/* If the length of the hostname is greater than pjproject can handle, go no further */
-			pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
 			return -1;
 		}
 
@@ -195,25 +194,20 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co
 		}
 	}
 
-	/* The provided contacts are acceptable, huzzah! */
-	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
 	return 0;
 }
 
-/*! \brief Callback function which prunes static contacts */
-static int registrar_prune_static(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-
-	return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0;
-}
-
 /*! \brief Internal function used to delete a contact from an AOR */
 static int registrar_delete_contact(void *obj, void *arg, int flags)
 {
 	struct ast_sip_contact *contact = obj;
 	const char *aor_name = arg;
 
+	/* Permanent contacts can't be deleted */
+	if (ast_tvzero(contact->expiration_time)) {
+		return 0;
+	}
+
 	ast_sip_location_delete_contact(contact);
 	if (!ast_strlen_zero(aor_name)) {
 		ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name);
@@ -270,7 +264,7 @@ static int build_path_data(pjsip_rx_data *rdata, struct ast_str **path_str)
 	}
 
 	*path_str = ast_str_create(64);
-	if (!path_str) {
+	if (!*path_str) {
 		return -1;
 	}
 
@@ -442,7 +436,8 @@ static int vec_contact_add(void *obj, void *arg, int flags)
  *
  * \return Nothing
  */
-static void remove_excess_contacts(struct ao2_container *contacts, unsigned int to_remove)
+static void remove_excess_contacts(struct ao2_container *contacts, struct ao2_container *response_contacts,
+	unsigned int to_remove)
 {
 	struct excess_contact_vector contact_vec;
 
@@ -482,11 +477,28 @@ static void remove_excess_contacts(struct ao2_container *contacts, unsigned int
 			contact->uri,
 			contact->aor,
 			contact->user_agent);
+
+		ao2_unlink(response_contacts, contact);
 	}
 
 	AST_VECTOR_FREE(&contact_vec);
 }
 
+/*! \brief Callback function which adds non-permanent contacts to a container */
+static int registrar_add_non_permanent(void *obj, void *arg, int flags)
+{
+	struct ast_sip_contact *contact = obj;
+	struct ao2_container *container = arg;
+
+	if (ast_tvzero(contact->expiration_time)) {
+		return 0;
+	}
+
+	ao2_link(container, contact);
+
+	return 0;
+}
+
 struct aor_core_response {
 	/*! Tx data to use for statefull response.  NULL for stateless response. */
 	pjsip_tx_data *tdata;
@@ -506,8 +518,10 @@ static void register_aor_core(pjsip_rx_data *rdata,
 	int added = 0;
 	int updated = 0;
 	int deleted = 0;
+	int permanent = 0;
 	int contact_count;
-	pjsip_contact_hdr *contact_hdr = NULL;
+	struct ao2_container *existing_contacts = NULL;
+	pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
 	struct registrar_contact_details details = { 0, };
 	pjsip_tx_data *tdata;
 	RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
@@ -523,15 +537,28 @@ static void register_aor_core(pjsip_rx_data *rdata,
 	char *call_id = NULL;
 	size_t alloc_size;
 
-	/* So we don't count static contacts against max_contacts we prune them out from the container */
-	ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
+	/* We create a single pool and use it throughout this function where we need one */
+	details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
+		"Contact Comparison", 1024, 256);
+	if (!details.pool) {
+		response->code = 500;
+		return;
+	}
 
-	if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) {
+	/* If there are any permanent contacts configured on the AOR we need to take them
+	 * into account when counting contacts.
+	 */
+	if (aor->permanent_contacts) {
+		permanent = ao2_container_count(aor->permanent_contacts);
+	}
+
+	if (registrar_validate_contacts(rdata, details.pool, contacts, aor, permanent, &added, &updated, &deleted)) {
 		/* The provided Contact headers do not conform to the specification */
 		ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
 		ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
 				ast_sorcery_object_get_id(endpoint));
 		response->code = 400;
+		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
 		return;
 	}
 
@@ -540,15 +567,29 @@ static void register_aor_core(pjsip_rx_data *rdata,
 		ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
 				ast_sorcery_object_get_id(endpoint));
 		response->code = 420;
+		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
 		return;
 	}
 
 	if (aor->remove_existing) {
 		/* Cumulative number of contacts affected by this registration */
 		contact_count = MAX(updated + added - deleted,  0);
+
+		/* We need to keep track of only existing contacts so we can later
+		 * remove them if need be.
+		 */
+		existing_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
+			NULL, ast_sorcery_object_id_compare);
+		if (!existing_contacts) {
+			response->code = 500;
+			pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
+			return;
+		}
+
+		ao2_callback(contacts, OBJ_NODATA, registrar_add_non_permanent, existing_contacts);
 	} else {
 		/* Total contacts after this registration */
-		contact_count = ao2_container_count(contacts) + added - deleted;
+		contact_count = ao2_container_count(contacts) - permanent + added - deleted;
 	}
 	if (contact_count > aor->max_contacts) {
 		/* Enforce the maximum number of contacts */
@@ -556,13 +597,8 @@ static void register_aor_core(pjsip_rx_data *rdata,
 		ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n",
 				ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts);
 		response->code = 403;
-		return;
-	}
-
-	details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
-		"Contact Comparison", 256, 256);
-	if (!details.pool) {
-		response->code = 500;
+		pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
+		ao2_cleanup(existing_contacts);
 		return;
 	}
 
@@ -595,7 +631,7 @@ static void register_aor_core(pjsip_rx_data *rdata,
 	}
 
 	/* Iterate each provided Contact header and add, update, or delete */
-	while ((contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
+	for (; (contact_hdr = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr->next)); pj_pool_reset(details.pool)) {
 		int expiration;
 		char contact_uri[pjsip_max_url_size];
 		RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
@@ -604,6 +640,13 @@ static void register_aor_core(pjsip_rx_data *rdata,
 			/* A star means to unregister everything, so do so for the possible contacts */
 			ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
 				registrar_delete_contact, (void *)aor_name);
+			/* If we are keeping track of existing contacts for removal then, well, there is
+			 * absolutely nothing left so no need to try to remove any.
+			 */
+			if (existing_contacts) {
+				ao2_ref(existing_contacts, -1);
+				existing_contacts = NULL;
+			}
 			break;
 		}
 
@@ -617,6 +660,14 @@ static void register_aor_core(pjsip_rx_data *rdata,
 		pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
 
 		contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details);
+
+		/* If a contact was returned and we need to keep track of existing contacts then it
+		 * should be removed.
+		 */
+		if (contact && existing_contacts) {
+			ao2_unlink(existing_contacts, contact);
+		}
+
 		if (!contact) {
 			int prune_on_boot;
 
@@ -672,6 +723,8 @@ static void register_aor_core(pjsip_rx_data *rdata,
 					aor_name,
 					expiration,
 					user_agent);
+
+			ao2_link(contacts, contact);
 		} else if (expiration) {
 			struct ast_sip_contact *contact_update;
 
@@ -712,6 +765,7 @@ static void register_aor_core(pjsip_rx_data *rdata,
 					aor_name,
 					expiration,
 					contact_update->user_agent);
+			ao2_link(contacts, contact_update);
 			ao2_cleanup(contact_update);
 		} else {
 			if (contact->prune_on_boot) {
@@ -749,24 +803,20 @@ static void register_aor_core(pjsip_rx_data *rdata,
 	 * that have not been updated/added/deleted as a result of this
 	 * REGISTER do so.
 	 *
-	 * The contacts container currently holds the existing contacts that
-	 * were not affected by this REGISTER.
+	 * The existing contacts container holds all contacts that were not
+	 * involved in this REGISTER.
+	 * The contacts container holds the current contacts of the AOR.
 	 */
-	if (aor->remove_existing) {
+	if (aor->remove_existing && existing_contacts) {
 		/* Total contacts after this registration */
-		contact_count = ao2_container_count(contacts) + updated + added;
+		contact_count = ao2_container_count(existing_contacts) + updated + added;
 		if (contact_count > aor->max_contacts) {
 			/* Remove excess existing contacts that expire the soonest */
-			remove_excess_contacts(contacts, contact_count - aor->max_contacts);
+			remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts);
 		}
+		ao2_ref(existing_contacts, -1);
 	}
 
-	/* Re-retrieve contacts.  Caller will clean up the original container. */
-	contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
-	if (!contacts) {
-		response->code = 500;
-		return;
-	}
 	response_contact = ao2_callback(contacts, 0, NULL, NULL);
 
 	/* Send a response containing all of the contacts (including static) that are present on this AOR */
@@ -782,7 +832,6 @@ static void register_aor_core(pjsip_rx_data *rdata,
 	registrar_add_date_header(tdata);
 
 	ao2_callback(contacts, 0, registrar_add_contact, tdata);
-	ao2_cleanup(contacts);
 
 	if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
 		expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));