diff --git a/bin/tests/system/resolver/ns4/named.noaa b/bin/tests/system/resolver/ns4/named.noaa
deleted file mode 100644
index be78cc2c94..0000000000
--- a/bin/tests/system/resolver/ns4/named.noaa
+++ /dev/null
@@ -1,12 +0,0 @@
-Copyright (C) Internet Systems Consortium, Inc. ("ISC")
-
-SPDX-License-Identifier: MPL-2.0
-
-This Source Code Form is subject to the terms of the Mozilla Public
-License, v. 2.0.  If a copy of the MPL was not distributed with this
-file, you can obtain one at https://mozilla.org/MPL/2.0/.
-
-See the COPYRIGHT file distributed with this work for additional
-information regarding copyright ownership.
-
-Add -T noaa.
diff --git a/bin/tests/system/resolver/tests.sh b/bin/tests/system/resolver/tests.sh
index 222b76838e..5b8821cacc 100755
--- a/bin/tests/system/resolver/tests.sh
+++ b/bin/tests/system/resolver/tests.sh
@@ -220,6 +220,10 @@ done
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=$((status + ret))
 
+stop_server ns4
+touch ns4/named.noaa
+start_server --noclean --restart --port ${PORT} ns4 || ret=1
+
 n=$((n + 1))
 echo_i "RT21594 regression test check setup ($n)"
 ret=0
@@ -256,6 +260,10 @@ grep "status: NXDOMAIN" dig.ns5.out.${n} >/dev/null || ret=1
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=$((status + ret))
 
+stop_server ns4
+rm ns4/named.noaa
+start_server --noclean --restart --port ${PORT} ns4 || ret=1
+
 n=$((n + 1))
 echo_i "check that replacement of additional data by a negative cache no data entry clears the additional RRSIGs ($n)"
 ret=0
diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h
index cb0a8d327b..5fcdc9f794 100644
--- a/lib/dns/include/dns/rdataset.h
+++ b/lib/dns/include/dns/rdataset.h
@@ -54,6 +54,8 @@
 #include <dns/rdatastruct.h>
 #include <dns/types.h>
 
+#define DNS_RDATASET_MAXADDITIONAL 13
+
 /* Fixed RRSet helper macros */
 
 #define DNS_RDATASET_LENGTH 2;
@@ -524,7 +526,8 @@ dns_rdataset_towirepartial(dns_rdataset_t   *rdataset,
 isc_result_t
 dns_rdataset_additionaldata(dns_rdataset_t	    *rdataset,
 			    const dns_name_t	    *owner_name,
-			    dns_additionaldatafunc_t add, void *arg);
+			    dns_additionaldatafunc_t add, void *arg,
+			    size_t limit);
 /*%<
  * For each rdata in rdataset, call 'add' for each name and type in the
  * rdata which is subject to additional section processing.
@@ -543,10 +546,15 @@ dns_rdataset_additionaldata(dns_rdataset_t	    *rdataset,
  *\li	If a call to dns_rdata_additionaldata() is not successful, the
  *	result returned will be the result of dns_rdataset_additionaldata().
  *
+ *\li	If the 'limit' is non-zero and the number of the rdatasets is larger
+ *	than the 'limit', no additional data will be generated.
+ *
  * Returns:
  *
  *\li	#ISC_R_SUCCESS
  *
+ *\li	#DNS_R_TOOMANYRECORDS in case rdataset count is larger than 'limit'
+ *
  *\li	Any error that dns_rdata_additionaldata() can return.
  */
 
diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c
index aadfaf2bb8..5781e6b96f 100644
--- a/lib/dns/qpcache.c
+++ b/lib/dns/qpcache.c
@@ -1530,10 +1530,11 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
 }
 
 static isc_result_t
-find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
-     dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
-     dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
-     dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
+qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
+	     dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
+	     dns_dbnode_t **nodep, dns_name_t *foundname,
+	     dns_rdataset_t *rdataset,
+	     dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
 	qpcnode_t *node = NULL;
 	isc_result_t result;
 	qpc_search_t search;
@@ -1975,10 +1976,11 @@ tree_exit:
 }
 
 static isc_result_t
-findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
-	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
-	    dns_name_t *dcname, dns_rdataset_t *rdataset,
-	    dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
+qpcache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
+		    isc_stdtime_t now, dns_dbnode_t **nodep,
+		    dns_name_t *foundname, dns_name_t *dcname,
+		    dns_rdataset_t *rdataset,
+		    dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
 	qpcnode_t *node = NULL;
 	isc_rwlock_t *lock = NULL;
 	isc_result_t result;
@@ -2150,10 +2152,10 @@ tree_exit:
 }
 
 static isc_result_t
-findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
-	     dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
-	     dns_rdataset_t *rdataset,
-	     dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
+qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+		     dns_rdatatype_t type, dns_rdatatype_t covers,
+		     isc_stdtime_t now, dns_rdataset_t *rdataset,
+		     dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
 	qpcache_t *qpdb = (qpcache_t *)db;
 	qpcnode_t *qpnode = (qpcnode_t *)node;
 	dns_slabheader_t *header = NULL, *header_next = NULL;
@@ -2552,7 +2554,7 @@ free_qpdb(qpcache_t *qpdb, bool log) {
 }
 
 static void
-qpdb_destroy(dns_db_t *arg) {
+qpcache_destroy(dns_db_t *arg) {
 	qpcache_t *qpdb = (qpcache_t *)arg;
 	bool want_free = false;
 	unsigned int i;
@@ -2680,8 +2682,8 @@ new_qpcnode(qpcache_t *qpdb, const dns_name_t *name) {
 }
 
 static isc_result_t
-findnode(dns_db_t *db, const dns_name_t *name, bool create,
-	 dns_dbnode_t **nodep DNS__DB_FLARG) {
+qpcache_findnode(dns_db_t *db, const dns_name_t *name, bool create,
+		 dns_dbnode_t **nodep DNS__DB_FLARG) {
 	qpcache_t *qpdb = (qpcache_t *)db;
 	qpcnode_t *node = NULL;
 	isc_result_t result;
@@ -2716,8 +2718,8 @@ unlock:
 }
 
 static void
-attachnode(dns_db_t *db, dns_dbnode_t *source,
-	   dns_dbnode_t **targetp DNS__DB_FLARG) {
+qpcache_attachnode(dns_db_t *db, dns_dbnode_t *source,
+		   dns_dbnode_t **targetp DNS__DB_FLARG) {
 	REQUIRE(VALID_QPDB((qpcache_t *)db));
 	REQUIRE(targetp != NULL && *targetp == NULL);
 
@@ -2731,7 +2733,7 @@ attachnode(dns_db_t *db, dns_dbnode_t *source,
 }
 
 static void
-detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) {
+qpcache_detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) {
 	qpcache_t *qpdb = (qpcache_t *)db;
 	qpcnode_t *node = NULL;
 	bool want_free = false;
@@ -2786,8 +2788,8 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) {
 }
 
 static isc_result_t
-createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED,
-	       dns_dbiterator_t **iteratorp) {
+qpcache_createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED,
+		       dns_dbiterator_t **iteratorp) {
 	qpcache_t *qpdb = (qpcache_t *)db;
 	qpc_dbit_t *qpdbiter = NULL;
 
@@ -2809,9 +2811,9 @@ createiterator(dns_db_t *db, unsigned int options ISC_ATTR_UNUSED,
 }
 
 static isc_result_t
-allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
-	     unsigned int options, isc_stdtime_t now,
-	     dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
+qpcache_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+		     unsigned int options, isc_stdtime_t now,
+		     dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
 	qpcache_t *qpdb = (qpcache_t *)db;
 	qpcnode_t *qpnode = (qpcnode_t *)node;
 	qpc_rditer_t *iterator = NULL;
@@ -3386,9 +3388,10 @@ expire_ttl_headers(qpcache_t *qpdb, unsigned int locknum,
 		   isc_stdtime_t now, bool cache_is_overmem DNS__DB_FLARG);
 
 static isc_result_t
-addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
-	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
-	    dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
+qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+		    isc_stdtime_t now, dns_rdataset_t *rdataset,
+		    unsigned int options,
+		    dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
 	qpcache_t *qpdb = (qpcache_t *)db;
 	qpcnode_t *qpnode = (qpcnode_t *)node;
 	isc_region_t region;
@@ -3569,8 +3572,9 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
 }
 
 static isc_result_t
-deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
-	       dns_rdatatype_t type, dns_rdatatype_t covers DNS__DB_FLARG) {
+qpcache_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
+		       dns_dbversion_t *version, dns_rdatatype_t type,
+		       dns_rdatatype_t covers DNS__DB_FLARG) {
 	qpcache_t *qpdb = (qpcache_t *)db;
 	qpcnode_t *qpnode = (qpcnode_t *)node;
 	isc_result_t result;
@@ -4378,17 +4382,17 @@ setmaxtypepername(dns_db_t *db, uint32_t value) {
 }
 
 static dns_dbmethods_t qpdb_cachemethods = {
-	.destroy = qpdb_destroy,
-	.findnode = findnode,
-	.find = find,
-	.findzonecut = findzonecut,
-	.attachnode = attachnode,
-	.detachnode = detachnode,
-	.createiterator = createiterator,
-	.findrdataset = findrdataset,
-	.allrdatasets = allrdatasets,
-	.addrdataset = addrdataset,
-	.deleterdataset = deleterdataset,
+	.destroy = qpcache_destroy,
+	.findnode = qpcache_findnode,
+	.find = qpcache_find,
+	.findzonecut = qpcache_findzonecut,
+	.attachnode = qpcache_attachnode,
+	.detachnode = qpcache_detachnode,
+	.createiterator = qpcache_createiterator,
+	.findrdataset = qpcache_findrdataset,
+	.allrdatasets = qpcache_allrdatasets,
+	.addrdataset = qpcache_addrdataset,
+	.deleterdataset = qpcache_deleterdataset,
 	.nodecount = nodecount,
 	.getoriginnode = getoriginnode,
 	.getrrsetstats = getrrsetstats,
diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c
index bfff5f116a..af4f1844dc 100644
--- a/lib/dns/qpzone.c
+++ b/lib/dns/qpzone.c
@@ -1503,10 +1503,11 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp,
 }
 
 static isc_result_t
-findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
-	     dns_rdatatype_t type, dns_rdatatype_t covers,
-	     isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
-	     dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
+qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
+		    dns_dbversion_t *dbversion, dns_rdatatype_t type,
+		    dns_rdatatype_t covers, isc_stdtime_t now ISC_ATTR_UNUSED,
+		    dns_rdataset_t *rdataset,
+		    dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
 	qpzonedb_t *qpdb = (qpzonedb_t *)db;
 	qpznode_t *node = (qpznode_t *)dbnode;
 	dns_slabheader_t *header = NULL, *header_next = NULL;
@@ -2504,8 +2505,8 @@ findnodeintree(qpzonedb_t *qpdb, const dns_name_t *name, bool create,
 }
 
 static isc_result_t
-findnode(dns_db_t *db, const dns_name_t *name, bool create,
-	 dns_dbnode_t **nodep DNS__DB_FLARG) {
+qpzone_findnode(dns_db_t *db, const dns_name_t *name, bool create,
+		dns_dbnode_t **nodep DNS__DB_FLARG) {
 	qpzonedb_t *qpdb = (qpzonedb_t *)db;
 
 	REQUIRE(VALID_QPZONE(qpdb));
@@ -2515,8 +2516,8 @@ findnode(dns_db_t *db, const dns_name_t *name, bool create,
 }
 
 static isc_result_t
-findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
-	      dns_dbnode_t **nodep DNS__DB_FLARG) {
+qpzone_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
+		     dns_dbnode_t **nodep DNS__DB_FLARG) {
 	qpzonedb_t *qpdb = (qpzonedb_t *)db;
 
 	REQUIRE(VALID_QPZONE(qpdb));
@@ -2564,9 +2565,9 @@ matchparams(dns_slabheader_t *header, qpz_search_t *search) {
 }
 
 static isc_result_t
-setup_delegation(qpz_search_t *search, dns_dbnode_t **nodep,
-		 dns_name_t *foundname, dns_rdataset_t *rdataset,
-		 dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
+qpzone_setup_delegation(qpz_search_t *search, dns_dbnode_t **nodep,
+			dns_name_t *foundname, dns_rdataset_t *rdataset,
+			dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
 	dns_name_t *zcname = NULL;
 	dns_typepair_t type;
 	qpznode_t *node = NULL;
@@ -3160,7 +3161,7 @@ again:
 }
 
 static isc_result_t
-check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
+qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
 	qpz_search_t *search = arg;
 	dns_slabheader_t *header = NULL, *header_next = NULL;
 	dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL;
@@ -3287,11 +3288,11 @@ check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
 }
 
 static isc_result_t
-find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
-     dns_rdatatype_t type, unsigned int options,
-     isc_stdtime_t now ISC_ATTR_UNUSED, dns_dbnode_t **nodep,
-     dns_name_t *foundname, dns_rdataset_t *rdataset,
-     dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
+qpzone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
+	    dns_rdatatype_t type, unsigned int options,
+	    isc_stdtime_t now ISC_ATTR_UNUSED, dns_dbnode_t **nodep,
+	    dns_name_t *foundname, dns_rdataset_t *rdataset,
+	    dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
 	isc_result_t result;
 	qpzonedb_t *qpdb = (qpzonedb_t *)db;
 	qpznode_t *node = NULL;
@@ -3361,7 +3362,7 @@ find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
 		isc_result_t tresult;
 
 		dns_qpchain_node(&search.chain, i, NULL, (void **)&n, NULL);
-		tresult = check_zonecut(n, &search DNS__DB_FLARG_PASS);
+		tresult = qpzone_check_zonecut(n, &search DNS__DB_FLARG_PASS);
 		if (tresult != DNS_R_CONTINUE) {
 			result = tresult;
 			search.chain.len = i - 1;
@@ -3375,7 +3376,7 @@ find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
 	if (result == DNS_R_PARTIALMATCH) {
 	partial_match:
 		if (search.zonecut != NULL) {
-			result = setup_delegation(
+			result = qpzone_setup_delegation(
 				&search, nodep, foundname, rdataset,
 				sigrdataset DNS__DB_FLARG_PASS);
 			goto tree_exit;
@@ -3657,7 +3658,7 @@ found:
 			 * Return the delegation.
 			 */
 			NODE_UNLOCK(lock, &nlocktype);
-			result = setup_delegation(
+			result = qpzone_setup_delegation(
 				&search, nodep, foundname, rdataset,
 				sigrdataset DNS__DB_FLARG_PASS);
 			goto tree_exit;
@@ -3805,9 +3806,10 @@ tree_exit:
 }
 
 static isc_result_t
-allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
-	     unsigned int options, isc_stdtime_t now ISC_ATTR_UNUSED,
-	     dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
+qpzone_allrdatasets(dns_db_t *db, dns_dbnode_t *dbnode,
+		    dns_dbversion_t *dbversion, unsigned int options,
+		    isc_stdtime_t now ISC_ATTR_UNUSED,
+		    dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
 	qpzonedb_t *qpdb = (qpzonedb_t *)db;
 	qpznode_t *node = (qpznode_t *)dbnode;
 	qpz_version_t *version = (qpz_version_t *)dbversion;
@@ -4541,8 +4543,8 @@ dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
 }
 
 static isc_result_t
-createiterator(dns_db_t *db, unsigned int options,
-	       dns_dbiterator_t **iteratorp) {
+qpzone_createiterator(dns_db_t *db, unsigned int options,
+		      dns_dbiterator_t **iteratorp) {
 	qpzonedb_t *qpdb = (qpzonedb_t *)db;
 	qpdb_dbiterator_t *iter = NULL;
 
@@ -4580,9 +4582,11 @@ createiterator(dns_db_t *db, unsigned int options,
 }
 
 static isc_result_t
-addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
-	    isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
-	    unsigned int options, dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
+qpzone_addrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
+		   dns_dbversion_t *dbversion,
+		   isc_stdtime_t now ISC_ATTR_UNUSED, dns_rdataset_t *rdataset,
+		   unsigned int options,
+		   dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
 	isc_result_t result;
 	qpzonedb_t *qpdb = (qpzonedb_t *)db;
 	qpznode_t *node = (qpznode_t *)dbnode;
@@ -4709,9 +4713,10 @@ addrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
 }
 
 static isc_result_t
-subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
-		 dns_rdataset_t *rdataset, unsigned int options,
-		 dns_rdataset_t *newrdataset DNS__DB_FLARG) {
+qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
+			dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
+			unsigned int options,
+			dns_rdataset_t *newrdataset DNS__DB_FLARG) {
 	qpzonedb_t *qpdb = (qpzonedb_t *)db;
 	qpznode_t *node = (qpznode_t *)dbnode;
 	qpz_version_t *version = (qpz_version_t *)dbversion;
@@ -4900,8 +4905,9 @@ unlock:
 }
 
 static isc_result_t
-deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_dbversion_t *dbversion,
-	       dns_rdatatype_t type, dns_rdatatype_t covers DNS__DB_FLARG) {
+qpzone_deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode,
+		      dns_dbversion_t *dbversion, dns_rdatatype_t type,
+		      dns_rdatatype_t covers DNS__DB_FLARG) {
 	qpzonedb_t *qpdb = (qpzonedb_t *)db;
 	qpznode_t *node = (qpznode_t *)dbnode;
 	qpz_version_t *version = (qpz_version_t *)dbversion;
@@ -4995,9 +5001,10 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
 	dns_rdataset_init(&rdataset_aaaa);
 	dns_rdataset_init(&sigrdataset_aaaa);
 
-	result = find(ctx->db, name, ctx->version, dns_rdatatype_a,
-		      DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a, name_a,
-		      &rdataset_a, &sigrdataset_a DNS__DB_FLARG_PASS);
+	result = qpzone_find(ctx->db, name, ctx->version, dns_rdatatype_a,
+			     DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a,
+			     name_a, &rdataset_a,
+			     &sigrdataset_a DNS__DB_FLARG_PASS);
 	if (result == DNS_R_GLUE) {
 		glue = new_gluelist(ctx->db->mctx, name_a);
 
@@ -5013,10 +5020,10 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
 		}
 	}
 
-	result = find(ctx->db, name, ctx->version, dns_rdatatype_aaaa,
-		      DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_aaaa,
-		      name_aaaa, &rdataset_aaaa,
-		      &sigrdataset_aaaa DNS__DB_FLARG_PASS);
+	result = qpzone_find(ctx->db, name, ctx->version, dns_rdatatype_aaaa,
+			     DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_aaaa,
+			     name_aaaa, &rdataset_aaaa,
+			     &sigrdataset_aaaa DNS__DB_FLARG_PASS);
 	if (result == DNS_R_GLUE) {
 		if (glue == NULL) {
 			glue = new_gluelist(ctx->db->mctx, name_aaaa);
@@ -5189,7 +5196,7 @@ newglue(dns_db_t *db, qpz_version_t *version, qpznode_t *node,
 	dns_name_copy(&node->name, ctx.nodename);
 
 	(void)dns_rdataset_additionaldata(rdataset, dns_rootname,
-					  glue_nsdname_cb, &ctx);
+					  glue_nsdname_cb, &ctx, 0);
 
 	return ctx.glue_list;
 }
@@ -5377,22 +5384,22 @@ static dns_dbmethods_t qpdb_zonemethods = {
 	.newversion = newversion,
 	.attachversion = attachversion,
 	.closeversion = closeversion,
-	.findnode = findnode,
-	.find = find,
+	.findnode = qpzone_findnode,
+	.find = qpzone_find,
 	.attachnode = attachnode,
 	.detachnode = detachnode,
-	.createiterator = createiterator,
-	.findrdataset = findrdataset,
-	.allrdatasets = allrdatasets,
-	.addrdataset = addrdataset,
-	.subtractrdataset = subtractrdataset,
-	.deleterdataset = deleterdataset,
+	.createiterator = qpzone_createiterator,
+	.findrdataset = qpzone_findrdataset,
+	.allrdatasets = qpzone_allrdatasets,
+	.addrdataset = qpzone_addrdataset,
+	.subtractrdataset = qpzone_subtractrdataset,
+	.deleterdataset = qpzone_deleterdataset,
 	.issecure = issecure,
 	.nodecount = nodecount,
 	.setloop = setloop,
 	.getoriginnode = getoriginnode,
 	.getnsec3parameters = getnsec3parameters,
-	.findnsec3node = findnsec3node,
+	.findnsec3node = qpzone_findnsec3node,
 	.setsigningtime = setsigningtime,
 	.getsigningtime = getsigningtime,
 	.getsize = getsize,
diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c
index 9a0ee35b4e..1a6dc4d551 100644
--- a/lib/dns/rdataset.c
+++ b/lib/dns/rdataset.c
@@ -507,7 +507,8 @@ dns_rdataset_towire(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
 isc_result_t
 dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
 			    const dns_name_t *owner_name,
-			    dns_additionaldatafunc_t add, void *arg) {
+			    dns_additionaldatafunc_t add, void *arg,
+			    size_t limit) {
 	dns_rdata_t rdata = DNS_RDATA_INIT;
 	isc_result_t result;
 
@@ -519,6 +520,10 @@ dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
 	REQUIRE(DNS_RDATASET_VALID(rdataset));
 	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
 
+	if (limit != 0 && dns_rdataset_count(rdataset) > limit) {
+		return DNS_R_TOOMANYRECORDS;
+	}
+
 	result = dns_rdataset_first(rdataset);
 	if (result != ISC_R_SUCCESS) {
 		return result;
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index cd5a780ad8..7c5c3c0962 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -8506,9 +8506,6 @@ rctx_answer_any(respctx_t *rctx) {
 		rdataset->attributes |= DNS_RDATASETATTR_ANSWER;
 		rdataset->attributes |= DNS_RDATASETATTR_CACHE;
 		rdataset->trust = rctx->trust;
-
-		(void)dns_rdataset_additionaldata(rdataset, rctx->aname,
-						  check_related, rctx);
 	}
 
 	return ISC_R_SUCCESS;
@@ -8556,7 +8553,8 @@ rctx_answer_match(respctx_t *rctx) {
 	rctx->ardataset->attributes |= DNS_RDATASETATTR_CACHE;
 	rctx->ardataset->trust = rctx->trust;
 	(void)dns_rdataset_additionaldata(rctx->ardataset, rctx->aname,
-					  check_related, rctx);
+					  check_related, rctx,
+					  DNS_RDATASET_MAXADDITIONAL);
 
 	for (sigrdataset = ISC_LIST_HEAD(rctx->aname->list);
 	     sigrdataset != NULL;
@@ -8763,7 +8761,8 @@ rctx_authority_positive(respctx_t *rctx) {
 					 */
 					(void)dns_rdataset_additionaldata(
 						rdataset, name, check_related,
-						rctx);
+						rctx,
+						DNS_RDATASET_MAXADDITIONAL);
 					done = true;
 				}
 			}
@@ -9270,8 +9269,11 @@ rctx_referral(respctx_t *rctx) {
 	 */
 	INSIST(rctx->ns_rdataset != NULL);
 	FCTX_ATTR_SET(fctx, FCTX_ATTR_GLUING);
+	/*
+	 * We want to append **all** the GLUE records here.
+	 */
 	(void)dns_rdataset_additionaldata(rctx->ns_rdataset, rctx->ns_name,
-					  check_related, rctx);
+					  check_related, rctx, 0);
 #if CHECK_FOR_GLUE_IN_ANSWER
 	/*
 	 * Look in the answer section for "glue" that is incorrectly
@@ -9386,7 +9388,8 @@ again:
 			if (CHASE(rdataset)) {
 				rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
 				(void)dns_rdataset_additionaldata(
-					rdataset, name, check_related, rctx);
+					rdataset, name, check_related, rctx,
+					DNS_RDATASET_MAXADDITIONAL);
 				rescan = true;
 			}
 		}
diff --git a/lib/ns/query.c b/lib/ns/query.c
index ee7b83a4f7..0521ff1a6b 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -2140,7 +2140,8 @@ addname:
 	if (trdataset != NULL && dns_rdatatype_followadditional(type)) {
 		if (client->additionaldepth++ < client->view->max_restarts) {
 			eresult = dns_rdataset_additionaldata(
-				trdataset, fname, query_additional_cb, qctx);
+				trdataset, fname, query_additional_cb, qctx,
+				DNS_RDATASET_MAXADDITIONAL);
 		}
 		client->additionaldepth--;
 	}
@@ -2238,7 +2239,7 @@ regular:
 	 * We don't care if dns_rdataset_additionaldata() fails.
 	 */
 	(void)dns_rdataset_additionaldata(rdataset, name, query_additional_cb,
-					  qctx);
+					  qctx, DNS_RDATASET_MAXADDITIONAL);
 	CTRACE(ISC_LOG_DEBUG(3), "query_additional: done");
 }
 
