diff --git a/include/asterisk/res_pjsip_pubsub.h b/include/asterisk/res_pjsip_pubsub.h
index e9d59a0851ae571dacd174563ec24bdcfdf763a0..4309a099e71214a676c0bfb491425917876556b9 100644
--- a/include/asterisk/res_pjsip_pubsub.h
+++ b/include/asterisk/res_pjsip_pubsub.h
@@ -545,6 +545,29 @@ void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscrip
  */
 struct ao2_container *ast_sip_subscription_get_datastores(const struct ast_sip_subscription *subscription);
 
+/*!
+ * \since 13.31.0
+ * \since 16.8.0
+ * \since 17.2.0
+ * \brief Set persistence data for a subscription
+ *
+ * \param subscription The subscription to set persistence data on
+ * \param persistence_data The persistence data to set
+ *
+ * \note This steals the reference to persistence_data
+ */
+void ast_sip_subscription_set_persistence_data(struct ast_sip_subscription *subscription, struct ast_json *persistence_data);
+
+/*!
+ * \since 13.31.0
+ * \since 16.8.0
+ * \since 17.2.0
+ * \brief Retrieve persistence data for a subscription
+ *
+ * \param subscription The subscription to retrieve persistence data from
+ */
+const struct ast_json *ast_sip_subscription_get_persistence_data(const struct ast_sip_subscription *subscription);
+
 /*!
  * \brief Register a subscription handler
  *
diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c
index a13995faca907659f8e3b0eb2e766dddf287de67..3934a8a0fb294a54123f23886ca5ea0bf14df772 100644
--- a/res/res_pjsip_dialog_info_body_generator.c
+++ b/res/res_pjsip_dialog_info_body_generator.c
@@ -60,51 +60,15 @@ static void *dialog_info_allocate_body(void *data)
 	return ast_sip_presence_xml_create_node(state_data->pool, NULL, "dialog-info");
 }
 
-static struct ast_datastore *dialog_info_xml_state_find_or_create(struct ao2_container *datastores)
-{
-	struct ast_datastore *datastore = ast_datastores_find(datastores, "dialog-info+xml");
-
-	if (datastore) {
-		return datastore;
-	}
-
-	datastore = ast_datastores_alloc_datastore(&dialog_info_xml_datastore, "dialog-info+xml");
-	if (!datastore) {
-		return NULL;
-	}
-	datastore->data = ast_calloc(1, sizeof(struct dialog_info_xml_state));
-	if (!datastore->data || ast_datastores_add(datastores, datastore)) {
-		ao2_ref(datastore, -1);
-		return NULL;
-	}
-
-	return datastore;
-}
-
-static unsigned int dialog_info_xml_get_version(struct ao2_container *datastores, unsigned int *version)
-{
-	struct ast_datastore *datastore = dialog_info_xml_state_find_or_create(datastores);
-	struct dialog_info_xml_state *state;
-
-	if (!datastore) {
-		return -1;
-	}
-
-	state = datastore->data;
-	*version = state->version++;
-	ao2_ref(datastore, -1);
-
-	return 0;
-}
-
 static int dialog_info_generate_body_content(void *body, void *data)
 {
 	pj_xml_node *dialog_info = body, *dialog, *state;
+	struct ast_datastore *datastore;
+	struct dialog_info_xml_state *datastore_state;
 	struct ast_sip_exten_state_data *state_data = data;
 	char *local = ast_strdupa(state_data->local), *stripped, *statestring = NULL;
 	char *pidfstate = NULL, *pidfnote = NULL;
 	enum ast_sip_pidf_state local_state;
-	unsigned int version;
 	char version_str[32], sanitized[PJSIP_MAX_URL_SIZE];
 	struct ast_sip_endpoint *endpoint = NULL;
 	unsigned int notify_early_inuse_ringing = 0;
@@ -113,9 +77,35 @@ static int dialog_info_generate_body_content(void *body, void *data)
 		return -1;
 	}
 
-	if (dialog_info_xml_get_version(state_data->datastores, &version)) {
-		ast_log(LOG_WARNING, "dialog-info+xml version could not be retrieved from datastore\n");
-		return -1;
+	datastore = ast_datastores_find(state_data->datastores, "dialog-info+xml");
+	if (!datastore) {
+		const struct ast_json *version_json = NULL;
+
+		datastore = ast_datastores_alloc_datastore(&dialog_info_xml_datastore, "dialog-info+xml");
+		if (!datastore) {
+			return -1;
+		}
+
+		datastore->data = ast_calloc(1, sizeof(struct dialog_info_xml_state));
+		if (!datastore->data || ast_datastores_add(state_data->datastores, datastore)) {
+			ao2_ref(datastore, -1);
+			return -1;
+		}
+		datastore_state = datastore->data;
+
+		if (state_data->sub) {
+			version_json = ast_sip_subscription_get_persistence_data(state_data->sub);
+		}
+
+		if (version_json) {
+			datastore_state->version = ast_json_integer_get(version_json);
+			datastore_state->version++;
+		} else {
+			datastore_state->version = 0;
+		}
+	} else {
+		datastore_state = datastore->data;
+		datastore_state->version++;
 	}
 
 	stripped = ast_strip_quoted(local, "<", ">");
@@ -130,9 +120,13 @@ static int dialog_info_generate_body_content(void *body, void *data)
 
 	ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "xmlns", "urn:ietf:params:xml:ns:dialog-info");
 
-	snprintf(version_str, sizeof(version_str), "%u", version);
+	snprintf(version_str, sizeof(version_str), "%u", datastore_state->version);
 	ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "version", version_str);
 
+	if (state_data->sub) {
+		ast_sip_subscription_set_persistence_data(state_data->sub, ast_json_integer_create(datastore_state->version));
+	}
+
 	ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "state", "full");
 	ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "entity", sanitized);
 
@@ -156,6 +150,8 @@ static int dialog_info_generate_body_content(void *body, void *data)
 		ast_sip_presence_xml_create_attr(state_data->pool, param, "pvalue", "no");
 	}
 
+	ao2_ref(datastore, -1);
+
 	return 0;
 }
 
diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c
index e26f25021a4558a8cd93b5d266eb72bd80a7d839..32e0adf540011c053c83c37c674ea1c20a9c7de1 100644
--- a/res/res_pjsip_pubsub.c
+++ b/res/res_pjsip_pubsub.c
@@ -132,6 +132,11 @@
 					and therefore the subscription must be deleted after an asterisk restart.
 					</synopsis>
 				</configOption>
+				<configOption name="generator_data">
+					<synopsis>If set, contains persistence data for all generators of content
+					for the subscription.
+					</synopsis>
+				</configOption>
 			</configObject>
 			<configObject name="resource_list">
 				<synopsis>Resource list configuration parameters.</synopsis>
@@ -389,6 +394,8 @@ struct subscription_persistence {
 	char contact_uri[PJSIP_MAX_URL_SIZE];
 	/*! Prune subscription on restart */
 	int prune_on_boot;
+	/*! Body generator specific persistence data */
+	struct ast_json *generator_data;
 };
 
 /*!
@@ -490,6 +497,8 @@ struct ast_sip_subscription {
 	unsigned int full_state;
 	/*! URI associated with the subscription */
 	pjsip_sip_uri *uri;
+	/*! Data to be persisted with the subscription */
+	struct ast_json *persistence_data;
 	/*! Name of resource being subscribed to */
 	char resource[0];
 };
@@ -615,6 +624,7 @@ static void subscription_persistence_destroy(void *obj)
 
 	ast_free(persistence->endpoint);
 	ast_free(persistence->tag);
+	ast_json_unref(persistence->generator_data);
 }
 
 /*! \brief Allocator for subscription persistence */
@@ -1198,6 +1208,7 @@ static void destroy_subscription(struct ast_sip_subscription *sub)
 
 	AST_VECTOR_FREE(&sub->children);
 	ao2_cleanup(sub->datastores);
+	ast_json_unref(sub->persistence_data);
 	ast_free(sub);
 }
 
@@ -1248,6 +1259,14 @@ static struct ast_sip_subscription *allocate_subscription(const struct ast_sip_s
 	pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, contact_uri);
 	pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
 
+	/* If there is any persistence information available for this subscription that was persisted
+	 * then make it available so that the NOTIFY has the correct state.
+	 */
+
+	if (tree->persistence && tree->persistence->generator_data) {
+		sub->persistence_data = ast_json_object_get(tree->persistence->generator_data, resource);
+	}
+
 	sub->handler = handler;
 	sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
 	sub->tree = ao2_bump(tree);
@@ -1446,11 +1465,10 @@ static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_e
 static struct sip_subscription_tree *create_subscription_tree(const struct ast_sip_subscription_handler *handler,
 		struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource,
 		struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree,
-		pj_status_t *dlg_status)
+		pj_status_t *dlg_status, struct subscription_persistence *persistence)
 {
 	struct sip_subscription_tree *sub_tree;
 	pjsip_dialog *dlg;
-	struct subscription_persistence *persistence;
 
 	sub_tree = allocate_subscription_tree(endpoint, rdata);
 	if (!sub_tree) {
@@ -1491,6 +1509,9 @@ static struct sip_subscription_tree *create_subscription_tree(const struct ast_s
 
 	sub_tree->notification_batch_interval = tree->notification_batch_interval;
 
+	/* Persistence information needs to be available for all the subscriptions */
+	sub_tree->persistence = ao2_bump(persistence);
+
 	sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);
 	if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {
 		sub_tree->is_list = 1;
@@ -1612,7 +1633,7 @@ static int sub_persistence_recreate(void *obj)
 		pj_status_t dlg_status;
 
 		sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator,
-			&tree, &dlg_status);
+			&tree, &dlg_status, persistence);
 		if (!sub_tree) {
 			if (dlg_status != PJ_EEXISTS) {
 				ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not create subscription tree.\n",
@@ -1630,7 +1651,6 @@ static int sub_persistence_recreate(void *obj)
 			ind->sub_tree = ao2_bump(sub_tree);
 			ind->expires = expires_header->ivalue;
 
-			sub_tree->persistence = ao2_bump(persistence);
 			subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_RECREATED);
 			if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) {
 				/* Could not send initial subscribe NOTIFY */
@@ -2644,6 +2664,28 @@ struct ao2_container *ast_sip_publication_get_datastores(const struct ast_sip_pu
 	return publication->datastores;
 }
 
+void ast_sip_subscription_set_persistence_data(struct ast_sip_subscription *subscription, struct ast_json *persistence_data)
+{
+	ast_json_unref(subscription->persistence_data);
+	subscription->persistence_data = persistence_data;
+
+	if (subscription->tree->persistence) {
+		if (!subscription->tree->persistence->generator_data) {
+			subscription->tree->persistence->generator_data = ast_json_object_create();
+			if (!subscription->tree->persistence->generator_data) {
+				return;
+			}
+		}
+		ast_json_object_set(subscription->tree->persistence->generator_data, subscription->resource,
+			ast_json_ref(persistence_data));
+	}
+}
+
+const struct ast_json *ast_sip_subscription_get_persistence_data(const struct ast_sip_subscription *subscription)
+{
+	return subscription->persistence_data;
+}
+
 AST_RWLIST_HEAD_STATIC(publish_handlers, ast_sip_publish_handler);
 
 static int publication_hash_fn(const void *obj, const int flags)
@@ -3005,7 +3047,7 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
 		return PJ_TRUE;
 	}
 
-	sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status);
+	sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status, NULL);
 	if (!sub_tree) {
 		if (dlg_status != PJ_EEXISTS) {
 			pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
@@ -4657,6 +4699,39 @@ static int persistence_tag_struct2str(const void *obj, const intptr_t *args, cha
 	return 0;
 }
 
+static int persistence_generator_data_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+	struct subscription_persistence *persistence = obj;
+	struct ast_json_error error;
+
+	/* We tolerate a failure of the JSON to load and instead start fresh, since this field
+	 * originates from the persistence code and not a user.
+	 */
+	persistence->generator_data = ast_json_load_string(var->value, &error);
+
+	return 0;
+}
+
+static int persistence_generator_data_struct2str(const void *obj, const intptr_t *args, char **buf)
+{
+	const struct subscription_persistence *persistence = obj;
+	char *value;
+
+	if (!persistence->generator_data) {
+		return 0;
+	}
+
+	value = ast_json_dump_string(persistence->generator_data);
+	if (!value) {
+		return -1;
+	}
+
+	*buf = ast_strdup(value);
+	ast_json_free(value);
+
+	return 0;
+}
+
 static int persistence_expires_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
 	struct subscription_persistence *persistence = obj;
@@ -5529,6 +5604,8 @@ static int load_module(void)
 		CHARFLDSET(struct subscription_persistence, contact_uri));
 	ast_sorcery_object_field_register(sorcery, "subscription_persistence", "prune_on_boot", "no", OPT_YESNO_T, 1,
 		FLDSET(struct subscription_persistence, prune_on_boot));
+	ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "generator_data", "",
+		persistence_generator_data_str2struct, persistence_generator_data_struct2str, NULL, 0, 0);
 
 	if (apply_list_configuration(sorcery)) {
 		ast_sched_context_destroy(sched);