diff --git a/lib/layer/pktcache.c b/lib/layer/pktcache.c
index 1b1057c1d519a9c6196d0924bef65b88428c475d..c4a50d0797a4a80c1ca2dbd052f6deb0f9484c9f 100644
--- a/lib/layer/pktcache.c
+++ b/lib/layer/pktcache.c
@@ -26,9 +26,9 @@
 #define DEFAULT_MAXTTL (15 * 60)
 #define DEFAULT_NOTTL (5) /* Short-time "no data" retention to avoid bursts */
 
-static inline uint8_t get_tag(struct kr_request *req)
+static inline uint8_t get_tag(struct kr_query *qry)
 {
-	return (req->options & QUERY_DNSSEC_WANT) ? KR_CACHE_SEC : KR_CACHE_PKT;
+	return (qry->flags & QUERY_DNSSEC_WANT) ? KR_CACHE_SEC : KR_CACHE_PKT;
 }
 
 static uint32_t limit_ttl(uint32_t ttl)
@@ -115,7 +115,7 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
 	}
 
 	/* Fetch either answer to original or minimized query */
-	uint8_t tag = get_tag(req);
+	uint8_t tag = get_tag(qry);
 	int ret = loot_cache(&txn, pkt, tag, qry);
 	kr_cache_txn_abort(&txn);
 	if (ret == 0) {
@@ -197,7 +197,7 @@ static int stash(knot_layer_t *ctx, knot_pkt_t *pkt)
 	};
 
 	/* Stash answer in the cache */
-	int ret = kr_cache_insert(&txn, get_tag(req), qname, qtype, &header, data);	
+	int ret = kr_cache_insert(&txn, get_tag(qry), qname, qtype, &header, data);	
 	if (ret != 0) {
 		kr_cache_txn_abort(&txn);
 	} else {
diff --git a/lib/layer/rrcache.c b/lib/layer/rrcache.c
index 2a3e6a150f139cbd8ff2ea1b316741f7147a64ae..f72dbf3f34852b0497db89c0cc5da8fcfc649a4c 100644
--- a/lib/layer/rrcache.c
+++ b/lib/layer/rrcache.c
@@ -125,7 +125,7 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
 	 * Only one step of the chain is resolved at a time.
 	 */
 	struct kr_cache *cache = &req->ctx->cache;
-	int ret = loot_cache(cache, pkt, qry, req->options & QUERY_DNSSEC_WANT);
+	int ret = loot_cache(cache, pkt, qry, (qry->flags & QUERY_DNSSEC_WANT));
 	if (ret == 0) {
 		DEBUG_MSG("=> satisfied from cache\n");
 		qry->flags |= QUERY_CACHED|QUERY_NO_MINIMIZE;
@@ -141,6 +141,7 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
 struct stash_baton
 {
 	struct kr_request *req;
+	struct kr_query *qry;
 	struct kr_cache_txn *txn;
 	unsigned timestamp;
 	uint32_t min_ttl;
@@ -149,7 +150,7 @@ struct stash_baton
 static int commit_rrsig(struct stash_baton *baton, knot_rrset_t *rr)
 {
 	/* If not doing secure resolution, ignore (unvalidated) RRSIGs. */
-	if (!(baton->req->options & QUERY_DNSSEC_WANT)) {
+	if (!(baton->qry->flags & QUERY_DNSSEC_WANT)) {
 		return kr_ok();
 	}
 	/* Commit covering RRSIG to a separate cache namespace. */
@@ -197,12 +198,13 @@ static int commit_rr(const char *key, void *val, void *data)
 	return kr_cache_insert_rr(baton->txn, rr, baton->timestamp);
 }
 
-static int stash_commit(map_t *stash, unsigned timestamp, struct kr_cache_txn *txn, struct kr_request *req)
+static int stash_commit(map_t *stash, struct kr_query *qry, struct kr_cache_txn *txn, struct kr_request *req)
 {
 	struct stash_baton baton = {
 		.req = req,
+		.qry = qry,
 		.txn = txn,
-		.timestamp = timestamp,
+		.timestamp = qry->timestamp.tv_sec,
 		.min_ttl = DEFAULT_MINTTL
 	};
 	return map_walk(stash, &commit_rr, &baton);
@@ -339,7 +341,7 @@ static int stash(knot_layer_t *ctx, knot_pkt_t *pkt)
 		struct kr_cache *cache = &req->ctx->cache;
 		struct kr_cache_txn txn;
 		if (kr_cache_txn_begin(cache, &txn, 0) == 0) {
-			ret = stash_commit(&stash, qry->timestamp.tv_sec, &txn, req);
+			ret = stash_commit(&stash, qry, &txn, req);
 			if (ret == 0) {
 				kr_cache_txn_commit(&txn);
 			} else {
diff --git a/lib/resolve.c b/lib/resolve.c
index 94084ce1730d26940d214cbb0806ae6ba871d6b6..c77b40cec9f3d6363d3ffbb441aa2ad2c0169bdf 100644
--- a/lib/resolve.c
+++ b/lib/resolve.c
@@ -154,10 +154,6 @@ static int edns_put(knot_pkt_t *pkt)
 static int edns_create(knot_pkt_t *pkt, knot_pkt_t *template, struct kr_request *req)
 {
 	pkt->opt_rr = knot_rrset_copy(req->ctx->opt_rr, &pkt->mm);
-	/* Set DO bit if set (DNSSEC requested). */
-	if (knot_pkt_has_dnssec(template) || (req->options & QUERY_DNSSEC_WANT)) {
-		knot_edns_set_do(pkt->opt_rr);
-	}
 	return knot_pkt_reserve(pkt, knot_edns_wire_size(pkt->opt_rr));
 }
 
@@ -175,6 +171,10 @@ static int answer_prepare(knot_pkt_t *answer, knot_pkt_t *query, struct kr_reque
 		if (ret != 0){
 			return ret;
 		}
+		/* Set DO bit if set (DNSSEC requested). */
+		if (knot_pkt_has_dnssec(query)) {
+			knot_edns_set_do(answer->opt_rr);
+		}
 	}
 	return kr_ok();
 }
@@ -197,10 +197,9 @@ static int answer_finalize(struct kr_request *request, int state)
 	return kr_ok();
 }
 
-static int query_finalize(struct kr_request *request, knot_pkt_t *pkt)
+static int query_finalize(struct kr_request *request, struct kr_query *qry, knot_pkt_t *pkt)
 {
 	/* Randomize query case (if not in safemode) */
-	struct kr_query *qry = kr_rplan_current(&request->rplan);
 	qry->secret = (qry->flags & QUERY_SAFEMODE) ? 0 : kr_rand_uint(UINT32_MAX);
 	knot_dname_t *qname_raw = (knot_dname_t *)knot_pkt_qname(pkt);
 	randomized_qname_case(qname_raw, qry->secret);
@@ -209,7 +208,10 @@ static int query_finalize(struct kr_request *request, knot_pkt_t *pkt)
 	knot_pkt_begin(pkt, KNOT_ADDITIONAL);
 	if (!(qry->flags & QUERY_SAFEMODE)) {
 		ret = edns_create(pkt, request->answer, request);
-		if (ret == 0) {
+		if (ret == 0) { /* Enable DNSSEC for query. */
+			if (qry->flags & QUERY_DNSSEC_WANT) {
+				knot_edns_set_do(pkt->opt_rr);
+			}
 			ret = edns_put(pkt);
 		}
 	}
@@ -229,9 +231,12 @@ int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pk
 	return KNOT_STATE_CONSUME;
 }
 
-int kr_resolve_query(struct kr_request *request, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype)
+static int resolve_query(struct kr_request *request, const knot_pkt_t *packet)
 {
 	struct kr_rplan *rplan = &request->rplan;
+	const knot_dname_t *qname = knot_pkt_qname(packet);
+	uint16_t qclass = knot_pkt_qclass(packet);
+	uint16_t qtype = knot_pkt_qtype(packet);
 	struct kr_query *qry = kr_rplan_push(rplan, NULL, qname, qclass, qtype);
 	if (!qry) {
 		return KNOT_STATE_FAIL;
@@ -239,6 +244,9 @@ int kr_resolve_query(struct kr_request *request, const knot_dname_t *qname, uint
 
 	/* Deferred zone cut lookup for this query. */
 	qry->flags |= QUERY_AWAIT_CUT;
+	if (knot_pkt_has_dnssec(packet)) {
+		qry->flags |= QUERY_DNSSEC_WANT;
+	}
 
 	/* Initialize answer packet */
 	knot_pkt_t *answer = request->answer;
@@ -266,11 +274,7 @@ int kr_resolve_consume(struct kr_request *request, knot_pkt_t *packet)
 		if (answer_prepare(request->answer, packet, request) != 0) {
 			return KNOT_STATE_FAIL;
 		}
-		/* Start query resolution */
-		const knot_dname_t *qname = knot_pkt_qname(packet);
-		uint16_t qclass = knot_pkt_qclass(packet);
-		uint16_t qtype = knot_pkt_qtype(packet);
-		return kr_resolve_query(request, qname, qclass, qtype);
+		return resolve_query(request, packet);
 	}
 
 	/* Different processing for network error */
@@ -336,6 +340,9 @@ static int zone_cut_subreq(struct kr_rplan *rplan, struct kr_query *parent,
 		return kr_error(ENOMEM);
 	}
 	next->flags |= QUERY_NO_MINIMIZE;
+	if (parent->flags & QUERY_DNSSEC_WANT) {
+		next->flags |= QUERY_DNSSEC_WANT;
+	}
 	return kr_ok();
 }
 
@@ -472,7 +479,7 @@ ns_election:
 	}
 
 	/* Prepare additional query */
-	int ret = query_finalize(request, packet);
+	int ret = query_finalize(request, qry, packet);
 	if (ret != 0) {
 		return KNOT_STATE_FAIL;
 	}
diff --git a/lib/resolve.h b/lib/resolve.h
index a6afb2ba65b65415c71573c858c3dcd99675bb1a..c373819b7d9fa25c2e8ab7c2227bf3405487a3f9 100644
--- a/lib/resolve.h
+++ b/lib/resolve.h
@@ -42,8 +42,10 @@
  * 		.alloc = (mm_alloc_t) mp_alloc
  * 	}
  * };
- * kr_resolve_begin(&req, ctx, answer);
- * int state = kr_resolve_query(&req, qname, qclass, qtype);
+ *
+ * // Setup and provide input query
+ * int state = kr_resolve_begin(&req, ctx, final_answer);
+ * state = kr_resolve_consume(&req, query);
  *
  * // Generate answer
  * while (state == KNOT_STATE_PRODUCE) {
@@ -126,16 +128,6 @@ struct kr_request {
  */
 int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pkt_t *answer);
 
-/**
- * Push new query for resolution to the state.
- * @param  request request state (if already has a question, this will be resolved first)
- * @param  qname
- * @param  qclass
- * @param  qtype
- * @return         PRODUCE|FAIL
- */
-int kr_resolve_query(struct kr_request *request, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype);
-
 /**
  * Consume input packet (may be either first query or answer to query originated from kr_resolve_produce())
  *
diff --git a/modules/stats/stats.c b/modules/stats/stats.c
index 3b449a9edad30bec43e86fa1fd7c62a54c9d66e6..7941bb5f0a6107602c2d078a82dc3f316e295bf4 100644
--- a/modules/stats/stats.c
+++ b/modules/stats/stats.c
@@ -162,7 +162,7 @@ static int collect(knot_layer_t *ctx)
 	/* Query parameters and transport mode */
 	if (knot_pkt_has_edns(param->answer)) {
 		stat_const_add(data, metric_query_edns, 1);
-		if (param->options & QUERY_DNSSEC_WANT) {
+		if (knot_pkt_has_dnssec(param->answer)) {
 			stat_const_add(data, metric_query_dnssec, 1);
 		}
 	}