diff --git a/daemon/worker.c b/daemon/worker.c
index a35bc171456f17b0ac9936543a50f15a3517e0c1..a518e2066dc345f277c1420a8f4c95847857a615 100644
--- a/daemon/worker.c
+++ b/daemon/worker.c
@@ -30,11 +30,7 @@ struct qr_task
 	knot_pkt_t *next_query;
 	uv_handle_t *next_handle;
 	uv_timer_t timeout;
-	union {
-		uv_write_t tcp_send;
-		uv_udp_send_t udp_send;
-		uv_connect_t connect;
-	} ioreq;
+	uv_connect_t connect;
 	struct {
 		union {
 			struct sockaddr_in ip4;
@@ -117,8 +113,6 @@ static void qr_task_timeout(uv_timer_t *req)
 {
 	struct qr_task *task = req->data;
 	if (task->next_handle) {
-		uv_cancel((uv_req_t *)&task->ioreq);
-		io_stop_read(task->next_handle);
 		qr_task_step(task, NULL);
 	}
 }
@@ -160,7 +154,8 @@ static void qr_task_on_connect(uv_connect_t *connect, int status)
 {
 	uv_stream_t *handle = connect->handle;
 	struct qr_task *task = connect->data;
-	if (status == 0) { /* Failed to connect */
+	/* Use only if succeeded, and the connection didn't change. */
+	if (status == 0 && ((uv_handle_t *)handle == task->next_handle)) {
 		qr_task_send(task, (uv_handle_t *)handle, NULL, task->next_query);
 	}
 }
@@ -177,10 +172,12 @@ static int qr_task_step(struct qr_task *task, knot_pkt_t *packet)
 	/* Cancel timeout if active, close handle. */
 	if (task->next_handle) {
 		if (!uv_is_closing(task->next_handle)) {
+			io_stop_read(task->next_handle);
 			uv_close(task->next_handle, (uv_close_cb) free);
 		}
 		uv_timer_stop(&task->timeout);
 		task->next_handle = NULL;
+		task->connect.handle = NULL;
 	}
 
 	/* Consume input and produce next query */
@@ -209,7 +206,7 @@ static int qr_task_step(struct qr_task *task, knot_pkt_t *packet)
 	/* Connect or issue query datagram */
 	task->next_handle->data = task;
 	if (sock_type == SOCK_STREAM) {
-		uv_connect_t *connect = &task->ioreq.connect;
+		uv_connect_t *connect = &task->connect;
 		connect->data = task;
 		if (uv_tcp_connect(connect, (uv_tcp_t *)task->next_handle, addr, qr_task_on_connect) != 0) {
 			return qr_task_step(task, NULL);
diff --git a/lib/layer/pktcache.c b/lib/layer/pktcache.c
index 050aec156255e35320b7e1c11b12af6f0289cdd5..15891294a1c874a3e10611f8787bbb53cc8acfa1 100644
--- a/lib/layer/pktcache.c
+++ b/lib/layer/pktcache.c
@@ -54,10 +54,9 @@ static void adjust_ttl(knot_rrset_t *rr, uint32_t drift)
 	}
 }
 
-static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, uint8_t tag, uint32_t timestamp)
+static int loot_cache_pkt(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *qname,
+                          uint16_t rrtype, uint8_t tag, uint32_t timestamp)
 {
-	const knot_dname_t *qname = knot_pkt_qname(pkt);
-	uint16_t rrtype = knot_pkt_qtype(pkt);
 	struct kr_cache_entry *entry;
 	entry = kr_cache_peek(txn, tag, qname, rrtype, &timestamp);
 	if (!entry) { /* Not in the cache */
@@ -91,6 +90,25 @@ static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, uint8_t tag, uint32_t
 	return ret;
 }
 
+/** @internal Try to find a shortcut directly to searched packet, otherwise try to find minimised QNAME. */
+static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, uint8_t tag, struct kr_query *qry)
+{
+	uint32_t timestamp = qry->timestamp.tv_sec;
+	const knot_dname_t *qname = qry->sname;
+	uint16_t rrtype = qry->stype;
+	int ret = loot_cache_pkt(txn, pkt, qname, rrtype, tag, timestamp);
+	if (ret == 0) { /* Signalize minimisation disabled */
+		qry->flags |= QUERY_NO_MINIMIZE;
+	} else { /* Retry with minimised name */
+		qname = knot_pkt_qname(pkt);
+		rrtype = knot_pkt_qtype(pkt);
+		if (!knot_dname_is_equal(qname, qry->sname)) {
+			ret = loot_cache_pkt(txn, pkt, qname, rrtype, tag, timestamp);
+		}
+	}
+	return ret;
+}
+
 static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
 {
 	struct kr_request *req = ctx->data;
@@ -103,24 +121,25 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
 		return ctx->state; /* Only IN class */
 	}
 
-	/* Fetch packet from cache */
+	/* Prepare read transaction */
 	namedb_txn_t txn;
 	struct kr_cache *cache = req->ctx->cache;
 	if (kr_cache_txn_begin(cache, &txn, NAMEDB_RDONLY) != 0) {
 		return ctx->state;
 	}
-	uint32_t timestamp = qry->timestamp.tv_sec;
-	if (loot_cache(&txn, pkt, get_tag(req->answer), timestamp) != 0) {
-		kr_cache_txn_abort(&txn);
-		return ctx->state;
-	}
 
-	/* Mark as solved from cache */
-	DEBUG_MSG("=> satisfied from cache\n");
-	qry->flags |= QUERY_CACHED;
-	knot_wire_set_qr(pkt->wire);
+	/* Fetch either answer to original or minimized query */
+	uint8_t tag = get_tag(req->answer);
+	int ret = loot_cache(&txn, pkt, tag, qry);
 	kr_cache_txn_abort(&txn);
-	return KNOT_STATE_DONE;
+	if (ret == 0) {
+		DEBUG_MSG("=> satisfied from cache\n");
+		qry->flags |= QUERY_CACHED;
+		pkt->parsed = pkt->size;
+		knot_wire_set_qr(pkt->wire);
+		return KNOT_STATE_DONE;
+	}
+	return ctx->state;
 }
 
 static uint32_t packet_ttl(knot_pkt_t *pkt)
diff --git a/lib/layer/rrcache.c b/lib/layer/rrcache.c
index 2b23742ae290efffd81af18a5dbf05e3b5fb40ee..ea885b6135df86d1dab8a726647766d35fa374b0 100644
--- a/lib/layer/rrcache.c
+++ b/lib/layer/rrcache.c
@@ -33,18 +33,28 @@ static int begin(knot_layer_t *ctx, void *module_param)
 }
 
 static int loot_rr(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *name,
-                   uint16_t rrtype, uint16_t rrclass, uint32_t timestamp)
+                  uint16_t rrclass, uint16_t rrtype, struct kr_query *qry)
 {
+	/* Check if record exists in cache */
+	uint32_t timestamp = qry->timestamp.tv_sec;
 	knot_rrset_t cache_rr;
 	knot_rrset_init(&cache_rr, (knot_dname_t *)name, rrtype, rrclass);
 	int ret = kr_cache_peek_rr(txn, &cache_rr, &timestamp);
 	if (ret != 0) {
 		return ret;
 	}
-	knot_rrset_t rr_copy = kr_cache_materialize(&cache_rr, timestamp, &pkt->mm);
-	if (rr_copy.rrs.rr_count == 0) {
-		return kr_error(ENOENT);
+
+	/* Update packet question */
+	if (!knot_dname_is_equal(knot_pkt_qname(pkt), name)) {
+		uint8_t header[KNOT_WIRE_HEADER_SIZE];
+		memcpy(header, pkt->wire, sizeof(header));
+		knot_pkt_clear(pkt);
+		memcpy(pkt->wire, header, sizeof(header));
+		knot_pkt_put_question(pkt, qry->sname, qry->sclass, qry->stype);
 	}
+
+	/* Update packet answer */
+	knot_rrset_t rr_copy = kr_cache_materialize(&cache_rr, timestamp, &pkt->mm);
 	ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, &rr_copy, KNOT_PF_FREE);
 	if (ret != 0) {
 		knot_rrset_clear(&rr_copy, &pkt->mm);
@@ -53,14 +63,31 @@ static int loot_rr(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *name,
 	return kr_ok();
 }
 
-static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, uint32_t timestamp)
+static int loot_cache_set(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *qname,
+                          uint16_t rrclass, uint16_t rrtype, struct kr_query *qry)
 {
-	const knot_dname_t *qname = knot_pkt_qname(pkt);
-	uint16_t rrclass = knot_pkt_qclass(pkt);
-	uint16_t rrtype = knot_pkt_qtype(pkt);
-	int ret = loot_rr(txn, pkt, qname, rrtype, rrclass, timestamp);
+	int ret = loot_rr(txn, pkt, qname, rrclass, rrtype, qry);
 	if (ret == kr_error(ENOENT) && rrtype != KNOT_RRTYPE_CNAME) { /* Chase CNAME if no direct hit */
-		ret = loot_rr(txn, pkt, qname, KNOT_RRTYPE_CNAME, rrclass, timestamp);
+		ret = loot_rr(txn, pkt, qname, rrclass, KNOT_RRTYPE_CNAME, qry);
+	}
+	return ret;
+}
+
+/** @internal Try to find a shortcut directly to searched record, otherwise try to find minimised QNAME. */
+static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, struct kr_query *qry)
+{
+	const knot_dname_t *qname = qry->sname;
+	uint16_t rrclass = qry->sclass;
+	uint16_t rrtype = qry->stype;
+	int ret = loot_cache_set(txn, pkt, qname, rrclass, rrtype, qry);
+	if (ret == 0) { /* Signalize minimisation disabled */
+		qry->flags |= QUERY_NO_MINIMIZE;
+	} else { /* Retry with minimised name */
+		qname = knot_pkt_qname(pkt);
+		rrtype = knot_pkt_qtype(pkt);
+		if (!knot_dname_is_equal(qname, qry->sname)) {
+			ret = loot_cache_set(txn, pkt, qname, rrclass, rrtype, qry);
+		}
 	}
 	return ret;
 }
@@ -77,21 +104,21 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
 	namedb_txn_t txn;
 	struct kr_cache *cache = req->ctx->cache;
 	if (kr_cache_txn_begin(cache, &txn, NAMEDB_RDONLY) != 0) {
-		return KNOT_STATE_CONSUME;
+		return ctx->state;
 	}
 
 	/* Reconstruct the answer from the cache,
 	 * it may either be a CNAME chain or direct answer.
 	 * Only one step of the chain is resolved at a time.
 	 */
-	uint32_t timestamp = qry->timestamp.tv_sec;
-	int ret = loot_cache(&txn, pkt, timestamp);
+	int ret = loot_cache(&txn, pkt, qry);
 	kr_cache_txn_abort(&txn);
 	if (ret == 0) {
 		DEBUG_MSG("=> satisfied from cache\n");
 		qry->flags |= QUERY_CACHED;
 		pkt->parsed = pkt->size;
 		knot_wire_set_qr(pkt->wire);
+		knot_wire_set_aa(pkt->wire);
 		return KNOT_STATE_DONE;
 	}
 	return ctx->state;
diff --git a/scripts/Dockerfile b/scripts/Dockerfile
index ce174414ea7ae7396cbb3393b7b9270fd6c6e618..6d5084bd3812cb037a9c92ab706ca350fe8e934e 100644
--- a/scripts/Dockerfile
+++ b/scripts/Dockerfile
@@ -9,6 +9,7 @@ ENV PREFIX /usr/local
 ENV BUILD_DIR /tmp/build
 ENV BUILD_IGNORE gmp nettle jansson gnutls lua
 ENV CFLAGS -DNDEBUG -O2 -g -fstack-protector
+ENV LDFLAGS -Wl,--as-needed
 
 # Expose port
 EXPOSE 53