diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h
index 37c49d9af3..e1f8c7246b 100644
--- a/include/asterisk/_private.h
+++ b/include/asterisk/_private.h
@@ -48,6 +48,7 @@ int ast_cel_engine_reload(void);	/*!< Provided by cel.c */
 int ast_ssl_init(void);                 /*!< Provided by ssl.c */
 int ast_test_init(void);            /*!< Provided by test.c */
 int ast_msg_init(void);             /*!< Provided by message.c */
+void ast_msg_shutdown(void);        /*!< Provided by message.c */
 
 /*!
  * \brief Reload asterisk modules.
diff --git a/main/asterisk.c b/main/asterisk.c
index 8e6d1a486d..e8b9b34dea 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -1702,6 +1702,7 @@ static int can_safely_quit(shutdown_nice_t niceness, int restart)
 	 * (if in batch mode). really_quit happens to call it again when running
 	 * the atexit handlers, otherwise this would be a bit early. */
 	ast_cdr_engine_term();
+	ast_msg_shutdown();
 
 	if (niceness == SHUTDOWN_NORMAL) {
 		time_t s, e;
diff --git a/main/message.c b/main/message.c
index 1ac9231e31..26fea1aca9 100644
--- a/main/message.c
+++ b/main/message.c
@@ -756,7 +756,18 @@ static void chan_cleanup(struct ast_channel *chan)
 	ast_channel_unlock(chan);
 }
 
-AST_THREADSTORAGE(msg_q_chan);
+static void destroy_msg_q_chan(void *data)
+{
+	struct ast_channel **chan = data;
+
+	if (!*chan) {
+		return;
+	}
+
+	ast_channel_release(*chan);
+}
+
+AST_THREADSTORAGE_CUSTOM(msg_q_chan, NULL, destroy_msg_q_chan);
 
 /*!
  * \internal
@@ -1318,3 +1329,8 @@ int ast_msg_init(void)
 
 	return res;
 }
+
+void ast_msg_shutdown(void)
+{
+	msg_q_tp = ast_taskprocessor_unreference(msg_q_tp);
+}