diff --git a/include/asterisk/app.h b/include/asterisk/app.h
index a998ed86d82f665bf58a09553b83ae7063192689..70cf7527091f76172da1836cb9bb9e40ec64584b 100644
--- a/include/asterisk/app.h
+++ b/include/asterisk/app.h
@@ -1341,13 +1341,14 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen def
 /*!
  * \since 12
  * \brief Publish a MWI state update via stasis
- * \param[in] mailbox The number identifying this mailbox
+ *
+ * \param[in] mailbox The mailbox identifier string.
  * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
  * \param[in] new_msgs The number of new messages in this mailbox
  * \param[in] old_msgs The number of old messages in this mailbox
+ *
  * \retval 0 Success
  * \retval -1 Failure
- * \since 12
  */
 #define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs) \
 	ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, NULL, NULL)
@@ -1355,15 +1356,16 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen def
 /*!
  * \since 12
  * \brief Publish a MWI state update associated with some channel
- * \param[in] mailbox The number identifying this mailbox
+ *
+ * \param[in] mailbox The mailbox identifier string.
  * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
  * \param[in] new_msgs The number of new messages in this mailbox
  * \param[in] old_msgs The number of old messages in this mailbox
  * \param[in] channel_id A unique identifier for a channel associated with this
  * change in mailbox state
+ *
  * \retval 0 Success
  * \retval -1 Failure
- * \since 12
  */
 #define ast_publish_mwi_state_channel(mailbox, context, new_msgs, old_msgs, channel_id) \
 	ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, channel_id, NULL)
@@ -1371,23 +1373,51 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen def
 /*!
  * \since 12
  * \brief Publish a MWI state update via stasis with all parameters
- * \param[in] mailbox The number identifying this mailbox
+ *
+ * \param[in] mailbox The mailbox identifier string.
  * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
  * \param[in] new_msgs The number of new messages in this mailbox
  * \param[in] old_msgs The number of old messages in this mailbox
  * \param[in] channel_id A unique identifier for a channel associated with this
+ * change in mailbox state
  * \param[in] eid The EID of the server that originally published the message
+ *
  * \retval 0 Success
  * \retval -1 Failure
- * \since 12
  */
 int ast_publish_mwi_state_full(
-			const char *mailbox,
-			const char *context,
-			int new_msgs,
-			int old_msgs,
-			const char *channel_id,
-			struct ast_eid *eid);
+	const char *mailbox,
+	const char *context,
+	int new_msgs,
+	int old_msgs,
+	const char *channel_id,
+	struct ast_eid *eid);
+
+/*!
+ * \since 12.2.0
+ * \brief Delete MWI state cached by stasis
+ *
+ * \param[in] mailbox The mailbox identifier string.
+ * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+#define ast_delete_mwi_state(mailbox, context) \
+	ast_delete_mwi_state_full(mailbox, context, NULL)
+
+/*!
+ * \since 12.2.0
+ * \brief Delete MWI state cached by stasis with all parameters
+ *
+ * \param[in] mailbox The mailbox identifier string.
+ * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
+ * \param[in] eid The EID of the server that originally published the message
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid);
 
 /*! \addtogroup StasisTopicsAndMessages
  * @{
@@ -1421,6 +1451,9 @@ struct ast_mwi_blob {
  * \since 12
  * \brief Create a \ref ast_mwi_state object
  *
+ * \param[in] mailbox The mailbox identifier string.
+ * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
+ *
  * \retval \ref ast_mwi_state object on success
  * \retval NULL on error
  */
diff --git a/main/app.c b/main/app.c
index ce0d16cdd3d25a8e64cefab5ae5a88a874ac167f..b6c9882583f28e98094511f1bc2e1ecadfb551d7 100644
--- a/main/app.c
+++ b/main/app.c
@@ -2821,36 +2821,51 @@ struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context)
 	return mwi_state;
 }
 
-int ast_publish_mwi_state_full(
-			const char *mailbox,
-			const char *context,
-			int new_msgs,
-			int old_msgs,
-			const char *channel_id,
-			struct ast_eid *eid)
+/*!
+ * \internal
+ * \brief Create a MWI state snapshot message.
+ * \since 12.2.0
+ *
+ * \param[in] mailbox The mailbox identifier string.
+ * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox)
+ * \param[in] new_msgs The number of new messages in this mailbox
+ * \param[in] old_msgs The number of old messages in this mailbox
+ * \param[in] channel_id A unique identifier for a channel associated with this
+ * change in mailbox state
+ * \param[in] eid The EID of the server that originally published the message
+ *
+ * \retval message on success.  Use ao2_cleanup() when done with it.
+ * \retval NULL on error.
+ */
+static struct stasis_message *mwi_state_create_message(
+	const char *mailbox,
+	const char *context,
+	int new_msgs,
+	int old_msgs,
+	const char *channel_id,
+	struct ast_eid *eid)
 {
-	RAII_VAR(struct ast_mwi_state *, mwi_state, NULL, ao2_cleanup);
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-	struct stasis_topic *mailbox_specific_topic;
+	struct ast_mwi_state *mwi_state;
+	struct stasis_message *message;
 
 	mwi_state = ast_mwi_create(mailbox, context);
 	if (!mwi_state) {
-		return -1;
+		return NULL;
 	}
 
 	mwi_state->new_msgs = new_msgs;
 	mwi_state->old_msgs = old_msgs;
 
 	if (!ast_strlen_zero(channel_id)) {
-		RAII_VAR(struct stasis_message *, chan_message,
-			stasis_cache_get(ast_channel_cache(),
-					ast_channel_snapshot_type(),
-					channel_id),
-			ao2_cleanup);
+		struct stasis_message *chan_message;
+
+		chan_message = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(),
+			channel_id);
 		if (chan_message) {
 			mwi_state->snapshot = stasis_message_data(chan_message);
 			ao2_ref(mwi_state->snapshot, +1);
 		}
+		ao2_cleanup(chan_message);
 	}
 
 	if (eid) {
@@ -2860,16 +2875,34 @@ int ast_publish_mwi_state_full(
 	}
 
 	/*
-	 * As far as stasis is concerned, all MWI events are internal.
+	 * XXX As far as stasis is concerned, all MWI events are local.
 	 *
-	 * We may in the future want to make MWI aggregate internal/external
+	 * We may in the future want to make MWI aggregate local/remote
 	 * message counts similar to how device state aggregates state.
 	 */
 	message = stasis_message_create_full(ast_mwi_state_type(), mwi_state, &ast_eid_default);
+	ao2_cleanup(mwi_state);
+	return message;
+}
+
+int ast_publish_mwi_state_full(
+	const char *mailbox,
+	const char *context,
+	int new_msgs,
+	int old_msgs,
+	const char *channel_id,
+	struct ast_eid *eid)
+{
+	struct ast_mwi_state *mwi_state;
+	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+	struct stasis_topic *mailbox_specific_topic;
+
+	message = mwi_state_create_message(mailbox, context, new_msgs, old_msgs, channel_id, eid);
 	if (!message) {
 		return -1;
 	}
 
+	mwi_state = stasis_message_data(message);
 	mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid);
 	if (!mailbox_specific_topic) {
 		return -1;
@@ -2880,6 +2913,54 @@ int ast_publish_mwi_state_full(
 	return 0;
 }
 
+int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid)
+{
+	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+	struct stasis_message *cached_msg;
+	struct stasis_message *clear_msg;
+	struct ast_mwi_state *mwi_state;
+	struct stasis_topic *mailbox_specific_topic;
+
+	msg = mwi_state_create_message(mailbox, context, 0, 0, NULL, eid);
+	if (!msg) {
+		return -1;
+	}
+
+	mwi_state = stasis_message_data(msg);
+
+	/*
+	 * XXX As far as stasis is concerned, all MWI events are local.
+	 *
+	 * For now, it is assumed that there is only one entity
+	 * maintaining the state of a particular mailbox.
+	 *
+	 * If we ever have multiple MWI event entities maintaining
+	 * the same mailbox that wish to delete their cached entry
+	 * we will need to do something about the race condition
+	 * potential between checking the cache and removing the
+	 * cache entry.
+	 */
+	cached_msg = stasis_cache_get_by_eid(ast_mwi_state_cache(),
+		ast_mwi_state_type(), mwi_state->uniqueid, &ast_eid_default);
+	if (!cached_msg) {
+		/* Nothing to clear */
+		return -1;
+	}
+	ao2_cleanup(cached_msg);
+
+	mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid);
+	if (!mailbox_specific_topic) {
+		return -1;
+	}
+
+	clear_msg = stasis_cache_clear_create(msg);
+	if (clear_msg) {
+		stasis_publish(mailbox_specific_topic, clear_msg);
+	}
+	ao2_cleanup(clear_msg);
+	return 0;
+}
+
 static const char *mwi_state_get_id(struct stasis_message *message)
 {
 	if (ast_mwi_state_type() == stasis_message_type(message)) {
diff --git a/res/res_mwi_external.c b/res/res_mwi_external.c
index a7531c5cbf652b4bea485d06488f5918817ea987..c3fc0eaf405c59ece461207099a66b7a242e9ebd 100644
--- a/res/res_mwi_external.c
+++ b/res/res_mwi_external.c
@@ -123,13 +123,13 @@ static void mwi_observe_delete(const void *obj)
 {
 	const struct ast_mwi_mailbox_object *mailbox = obj;
 
-	if (!mailbox->msgs_new && !mailbox->msgs_old) {
-		/* No need to post a count clearing event. */
-		return;
+	if (mailbox->msgs_new || mailbox->msgs_old) {
+		/* Post a count clearing event. */
+		ast_publish_mwi_state(ast_sorcery_object_get_id(mailbox), NULL, 0, 0);
 	}
 
-	/* Post a count clearing event. */
-	ast_publish_mwi_state(ast_sorcery_object_get_id(mailbox), NULL, 0, 0);
+	/* Post a cache remove event. */
+	ast_delete_mwi_state(ast_sorcery_object_get_id(mailbox), NULL);
 }
 
 static const struct ast_sorcery_observer mwi_observers = {