diff --git a/CHANGES b/CHANGES
index 66ffca5d058ea86064aa422a6f9a0d7c270149b2..37ec31931a7497d3061677d6e81b51e689beb507 100644
--- a/CHANGES
+++ b/CHANGES
@@ -90,6 +90,17 @@ Core:
  * libedit is no longer available as an embedded library and must be provided
    by the system.
 
+------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 15.3.0 to Asterisk 15.4.0 ------------
+------------------------------------------------------------------------------
+
+res_pjproject
+------------------
+ * Added the "cache_pools" option to pjproject.conf.  Disabling the option
+   helps track down pool content mismanagement when using valgrind or
+   MALLOC_DEBUG.  The cache gets in the way of determining if the pool contents
+   are used after free and who freed it.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 15.2.0 to Asterisk 15.3.0 ------------
 ------------------------------------------------------------------------------
diff --git a/configs/samples/pjproject.conf.sample b/configs/samples/pjproject.conf.sample
index 82c81a1f6e0c16fcd4a0a132e04080e2d0982efa..03149c453975989249602f3a5cb90a11d132f5e7 100644
--- a/configs/samples/pjproject.conf.sample
+++ b/configs/samples/pjproject.conf.sample
@@ -5,6 +5,13 @@
 ;  NOTES: The name of this section in the pjproject.conf configuration file must
 ;         remain startup or the configuration will not be applied.
 ;
+;cache_pools = yes   ; Cache pjproject memory pools for performance
+                     ; Disable this option to help track down pool content
+                     ; mismanagement when using valgrind or MALLOC_DEBUG.
+                     ; The cache gets in the way of determining if the
+                     ; pool contents are used after being freed and who
+                     ; freed it.
+                     ; Default yes
 ;log_level=default   ; Initial maximum pjproject logging level to log
                      ; Valid values are: 0-6, and default
                      ;
diff --git a/include/asterisk/options.h b/include/asterisk/options.h
index 878748d169f2f3c065bc4bc140ee8758fbd1a335..78f596a8847d3d4c63cbc9c946b57967323b76cd 100644
--- a/include/asterisk/options.h
+++ b/include/asterisk/options.h
@@ -173,6 +173,11 @@ enum ast_option_flags {
 /*! Current linked pjproject maximum logging level */
 extern int ast_pjproject_max_log_level;
 
+#define DEFAULT_PJPROJECT_CACHE_POOLS	1
+
+/*! Current pjproject pool caching enable */
+extern int ast_option_pjproject_cache_pools;
+
 /*! Current pjproject logging level */
 extern int ast_option_pjproject_log_level;
 
diff --git a/include/asterisk/res_pjproject.h b/include/asterisk/res_pjproject.h
index 4993be610a0466982110fa9e4e0ed6a31ee6906f..17ebdd2016d6ad1f155dc6a9379b9ee0f5836e08 100644
--- a/include/asterisk/res_pjproject.h
+++ b/include/asterisk/res_pjproject.h
@@ -19,6 +19,9 @@
 #ifndef _RES_PJPROJECT_H
 #define _RES_PJPROJECT_H
 
+#include <pj/types.h>
+#include <pj/pool.h>
+
 /*!
  * \brief Retrieve a pjproject build option
  *
@@ -71,4 +74,27 @@ void ast_pjproject_log_intercept_begin(int fd);
  */
 void ast_pjproject_log_intercept_end(void);
 
+/*!
+ * \brief Initialize the caching pool factory.
+ * \since 13.21.0
+ *
+ * \param cp Caching pool factory to initialize
+ * \param policy Pool factory policy
+ * \param max_capacity Total capacity to be retained in the cache.  Zero disables caching.
+ *
+ * \return Nothing
+ */
+void ast_pjproject_caching_pool_init(pj_caching_pool *cp,
+	const pj_pool_factory_policy *policy, pj_size_t max_capacity);
+
+/*!
+ * \brief Destroy caching pool factory and all cached pools.
+ * \since 13.21.0
+ *
+ * \param cp Caching pool factory to destroy
+ *
+ * \return Nothing
+ */
+void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp);
+
 #endif /* _RES_PJPROJECT_H */
diff --git a/main/asterisk.c b/main/asterisk.c
index 4c15d231f772db48d0f457c0290dc47b9c756fc1..e348b2199fec39e57a77dc6ec98e75b210f7f201 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -331,6 +331,7 @@ int option_verbose;				/*!< Verbosity level */
 int option_debug;				/*!< Debug level */
 int ast_pjproject_max_log_level = -1;/* Default to -1 to know if we have read the level from pjproject yet. */
 int ast_option_pjproject_log_level;
+int ast_option_pjproject_cache_pools;
 double ast_option_maxload;			/*!< Max load avg on system */
 int ast_option_maxcalls;			/*!< Max number of active calls */
 int ast_option_maxfiles;			/*!< Max number of open file handles (files, sockets) */
@@ -3744,6 +3745,7 @@ static void read_pjproject_startup_options(void)
 	struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE | CONFIG_FLAG_NOREALTIME };
 
 	ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL;
+	ast_option_pjproject_cache_pools = DEFAULT_PJPROJECT_CACHE_POOLS;
 
 	cfg = ast_config_load2("pjproject.conf", "" /* core, can't reload */, config_flags);
 	if (!cfg
@@ -3762,6 +3764,8 @@ static void read_pjproject_startup_options(void)
 			} else if (MAX_PJ_LOG_MAX_LEVEL < ast_option_pjproject_log_level) {
 				ast_option_pjproject_log_level = MAX_PJ_LOG_MAX_LEVEL;
 			}
+		} else if (!strcasecmp(v->name, "cache_pools")) {
+			ast_option_pjproject_cache_pools = !ast_false(v->value);
 		}
 	}
 
diff --git a/res/res_pjproject.c b/res/res_pjproject.c
index f506a62fdcd8de6fa9c329d94d19f7aa6911b78b..ebd71b99bcc4f410f77b6f4b2c0f3cda5b990333 100644
--- a/res/res_pjproject.c
+++ b/res/res_pjproject.c
@@ -459,6 +459,18 @@ static struct ast_cli_entry pjproject_cli[] = {
 	AST_CLI_DEFINE(handle_pjproject_show_log_level, "Show the maximum active pjproject logging level"),
 };
 
+void ast_pjproject_caching_pool_init(pj_caching_pool *cp,
+	const pj_pool_factory_policy *policy, pj_size_t max_capacity)
+{
+	/* Passing a max_capacity of zero disables caching pools */
+	pj_caching_pool_init(cp, policy, ast_option_pjproject_cache_pools ? max_capacity : 0);
+}
+
+void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
+{
+	pj_caching_pool_destroy(cp);
+}
+
 static int load_module(void)
 {
 	ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n");
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index ca173a8af6b43b4fa15d44ca2bad8577cb7c92f9..9f6b5d115e6b283410a190c1c614a3d19d18df0c 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -4998,7 +4998,7 @@ static int unload_pjsip(void *data)
 	ast_pjsip_endpoint = NULL;
 
 	if (caching_pool.lock) {
-		pj_caching_pool_destroy(&caching_pool);
+		ast_pjproject_caching_pool_destroy(&caching_pool);
 	}
 
 	pj_shutdown();
@@ -5015,7 +5015,7 @@ static int load_pjsip(void)
 	 * example code from PJLIB. This can be adjusted
 	 * if necessary.
 	 */
-	pj_caching_pool_init(&caching_pool, NULL, 1024 * 1024);
+	ast_pjproject_caching_pool_init(&caching_pool, NULL, 1024 * 1024);
 	if (pjsip_endpt_create(&caching_pool.factory, "SIP", &ast_pjsip_endpoint) != PJ_SUCCESS) {
 		ast_log(LOG_ERROR, "Failed to create PJSIP endpoint structure. Aborting load\n");
 		goto error;
diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c
index 84f73c742bf4a107bbae88ea4fda4fddd4f728ef..22da805774cf248c1cd8246fd1a4353b82bffbaa 100644
--- a/res/res_pjsip/location.c
+++ b/res/res_pjsip/location.c
@@ -17,8 +17,8 @@
  */
 
 #include "asterisk.h"
-#include "pjsip.h"
-#include "pjlib.h"
+#include <pjsip.h>
+#include <pjlib.h>
 
 #include "asterisk/res_pjsip.h"
 #include "asterisk/logger.h"
diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c
index fa9e27f0025e092e343c1b713c02eaab4fb3f39a..ab035a2966a25d1e614c0e22bb2be45b00718ece 100644
--- a/res/res_pjsip_history.c
+++ b/res/res_pjsip_history.c
@@ -42,6 +42,7 @@
 #include "asterisk/netsock2.h"
 #include "asterisk/vector.h"
 #include "asterisk/lock.h"
+#include "asterisk/res_pjproject.h"
 
 #define HISTORY_INITIAL_SIZE 256
 
@@ -1369,7 +1370,7 @@ static int load_module(void)
 		ast_log(LOG_WARNING, "Unable to register history log level\n");
 	}
 
-	pj_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);
+	ast_pjproject_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);
 
 	AST_VECTOR_INIT(&vector_history, HISTORY_INITIAL_SIZE);
 
@@ -1387,7 +1388,7 @@ static int unload_module(void)
 	ast_sip_push_task_synchronous(NULL, clear_history_entries, NULL);
 	AST_VECTOR_FREE(&vector_history);
 
-	pj_caching_pool_destroy(&cachingpool);
+	ast_pjproject_caching_pool_destroy(&cachingpool);
 
 	if (log_level != -1) {
 		ast_logger_unregister_level("PJSIP_HISTORY");
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index d3273b463d9d85487c22644758ff727e960e4d00..b53b38ad799dfbe6ccf4a8d35d632a0f9e05527e 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -71,6 +71,9 @@
 #include "asterisk/smoother.h"
 #include "asterisk/uuid.h"
 #include "asterisk/test.h"
+#ifdef HAVE_PJPROJECT
+#include "asterisk/res_pjproject.h"
+#endif
 
 #define MAX_TIMESTAMP_SKEW	640
 
@@ -7376,7 +7379,7 @@ static void rtp_terminate_pjproject(void)
 		pj_thread_destroy(timer_thread);
 	}
 
-	pj_caching_pool_destroy(&cachingpool);
+	ast_pjproject_caching_pool_destroy(&cachingpool);
 	pj_shutdown();
 }
 #endif
@@ -7401,7 +7404,7 @@ static int load_module(void)
 		return AST_MODULE_LOAD_DECLINE;
 	}
 
-	pj_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);
+	ast_pjproject_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);
 
 	pool = pj_pool_create(&cachingpool.factory, "timer", 512, 512, NULL);
 
diff --git a/res/res_sdp_translator_pjmedia.c b/res/res_sdp_translator_pjmedia.c
index 772be272c8fb86967e02138befc1870229759818..676e740bc1eafbd875e4a0056596e2d90a234dd1 100644
--- a/res/res_sdp_translator_pjmedia.c
+++ b/res/res_sdp_translator_pjmedia.c
@@ -17,6 +17,11 @@
  */
 
 #include "asterisk.h"
+
+#include <pjlib.h>
+#include <pjmedia.h>
+
+#include "asterisk/res_pjproject.h"
 #include "asterisk/sdp_translator.h"
 #include "asterisk/sdp_options.h"
 #include "asterisk/vector.h"
@@ -27,10 +32,6 @@
 #include "asterisk/module.h"
 
 #include "asterisk/sdp.h"
-#ifdef HAVE_PJPROJECT
-#include <pjlib.h>
-#include <pjmedia.h>
-#endif
 
 /*** MODULEINFO
 	<depend>pjproject</depend>
@@ -573,7 +574,7 @@ static int load_module(void)
 	if (ast_sdp_register_translator(&pjmedia_translator)) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
-	pj_caching_pool_init(&sdp_caching_pool, NULL, 1024 * 1024);
+	ast_pjproject_caching_pool_init(&sdp_caching_pool, NULL, 1024 * 1024);
 	AST_TEST_REGISTER(pjmedia_to_sdp_test);
 	AST_TEST_REGISTER(sdp_to_pjmedia_test);
 
@@ -583,7 +584,7 @@ static int load_module(void)
 static int unload_module(void)
 {
 	ast_sdp_unregister_translator(&pjmedia_translator);
-	pj_caching_pool_destroy(&sdp_caching_pool);
+	ast_pjproject_caching_pool_destroy(&sdp_caching_pool);
 	AST_TEST_UNREGISTER(pjmedia_to_sdp_test);
 	AST_TEST_UNREGISTER(sdp_to_pjmedia_test);
 	return 0;
@@ -600,4 +601,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJMEDIA SDP Translato
 	.unload = unload_module,
 	.reload = reload_module,
 	.load_pri = AST_MODPRI_CHANNEL_DEPEND,
+	.requires = "res_pjproject",
 );