diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c
index 55a2a623fff657f4774b7fb738588dd46a832ef7..af7bba03e1c7b0e4b19ce53b6d4bdb390ac1e40e 100644
--- a/src/knot/ctl/remote.c
+++ b/src/knot/ctl/remote.c
@@ -468,7 +468,7 @@ static int remote_send_chunk(int c, knot_packet_t *pkt, const char* d,
                              uint16_t dlen, uint8_t* rwire, size_t rlen)
 {
 	int ret = KNOT_ERROR;
-	knot_packet_t *resp = knot_packet_new();
+	knot_packet_t *resp = knot_packet_new_mm(&pkt->mm);
 	if (!resp) {
 		return ret;
 	}
@@ -479,7 +479,7 @@ static int remote_send_chunk(int c, knot_packet_t *pkt, const char* d,
 		knot_packet_free(&resp);
 		return ret;
 	}
-	ret = knot_response_init_from_query(resp, pkt, 1);
+	ret = knot_response_init_from_query(resp, pkt);
 	if (ret != KNOT_EOK)  {
 		knot_packet_free(&resp);
 		return ret;
@@ -703,25 +703,23 @@ knot_packet_t* remote_query(const char *query, const knot_tsig_key_t *key)
 	}
 
 	/* Question section. */
-	knot_question_t q;
 	char *qname = strcdup(query, KNOT_CTL_REALM_EXT);
-	q.qname = knot_dname_new_from_str(qname, strlen(qname), 0);
-	if (!q.qname) {
+	knot_dname_t *dname = knot_dname_new_from_str(qname, strlen(qname), 0);
+	if (!dname) {
 		knot_packet_free(&qr);
 		free(qname);
 		return NULL;
 	}
-	q.qtype = KNOT_RRTYPE_ANY;
-	q.qclass = KNOT_CLASS_CH;
 
 	/* Cannot return != KNOT_EOK, but still. */
-	if (knot_query_set_question(qr, &q) != KNOT_EOK) {
+	if (knot_query_set_question(qr, dname, KNOT_CLASS_CH, KNOT_RRTYPE_ANY) != KNOT_EOK) {
 		knot_packet_free(&qr);
+		knot_dname_free(&dname);
 		free(qname);
 		return NULL;
 	}
 
-	knot_dname_release(q.qname);
+	knot_dname_free(&dname);
 	free(qname);
 
 	return qr;
diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c
index 934484e53e1c145ad6fcdb2294e47401ad7ab03a..244aa6b91c103149984144ca882a674094c74c43 100644
--- a/src/knot/server/notify.c
+++ b/src/knot/server/notify.c
@@ -63,14 +63,7 @@ static int notify_request(const knot_rrset_t *rrset,
 		return KNOT_ERROR;
 	}
 
-	knot_question_t question;
-
-	// this is ugly!!
-	question.qname = rrset->owner;
-	question.qtype = rrset->type;
-	question.qclass = rrset->rclass;
-
-	rc = knot_query_set_question(pkt, &question);
+	rc = knot_query_set_question(pkt, rrset->owner, rrset->rclass, rrset->type);
 	if (rc != KNOT_EOK) {
 		knot_packet_free(&pkt);
 		return KNOT_ERROR;
@@ -122,13 +115,13 @@ static int notify_request(const knot_rrset_t *rrset,
 int notify_create_response(knot_packet_t *request, uint8_t *buffer,
                            size_t *size)
 {
-	knot_packet_t *response = knot_packet_new();
+	knot_packet_t *response = knot_packet_new_mm(&request->mm);
 	CHECK_ALLOC_LOG(response, KNOT_ENOMEM);
 
 	/* Set maximum packet size. */
 	int rc = knot_packet_set_max_size(response, *size);
 	if (rc == KNOT_EOK) {
-		rc = knot_response_init_from_query(response, request, 1);
+		rc = knot_response_init_from_query(response, request);
 	}
 
 	/* Aggregated result check. */
diff --git a/src/knot/server/rrl.c b/src/knot/server/rrl.c
index f064d8fd87738c3b312905c877e9fab2940663d7..2bacd06e171ac098f685e3fd54e79075f09d82c3 100644
--- a/src/knot/server/rrl.c
+++ b/src/knot/server/rrl.c
@@ -99,8 +99,8 @@ static uint8_t rrl_clsid(rrl_req_t *p)
 	}
 
 	/* Check query type for spec. classes. */
-	if (p->qst) {
-		switch(p->qst->qtype) {
+	if (p->query) {
+		switch(knot_packet_qtype(p->query)) {
 		case KNOT_RRTYPE_ANY:      /* ANY spec. class */
 			return CLS_ANY;
 			break;
@@ -143,7 +143,7 @@ static int rrl_clsname(char *dst, size_t maxlen, uint8_t cls,
 		dbg_rrl_verb("%s: using zone/fallback name\n", __func__);
 		break;
 	default:
-		if (p->qst) dn = p->qst->qname;
+		if (p->query) dn = knot_packet_qname(p->query);
 		break;
 	}
 
diff --git a/src/knot/server/rrl.h b/src/knot/server/rrl.h
index 59ac9a6bfd622246763916f107a118e92750f24f..549a7b6bd392c37e8ad45aabfb6f3ed43cd7a3a9 100644
--- a/src/knot/server/rrl.h
+++ b/src/knot/server/rrl.h
@@ -78,7 +78,7 @@ typedef struct rrl_req {
 	const uint8_t *w;
 	uint16_t len;
 	unsigned flags;
-	const knot_question_t *qst;
+	knot_packet_t *query;
 } rrl_req_t;
 
 /*!
diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c
index 5f28d22c38772b8c927c4d3ea3388d1107319de2..de4a354f4dbf88043ddcc606b82080bdc0e6ecbb 100644
--- a/src/knot/server/udp-handler.c
+++ b/src/knot/server/udp-handler.c
@@ -220,7 +220,7 @@ int udp_handle(struct answer_ctx *ans, int fd,
 		rrl_req_t rrl_rq;
 		memset(&rrl_rq, 0, sizeof(rrl_req_t));
 		rrl_rq.w = qbuf; /* Wire */
-		rrl_rq.qst = &packet->question;
+		rrl_rq.query = packet;
 
 		rcu_read_lock();
 		rrl_rq.flags = packet->flags;
diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c
index e21e36a659fb6013d621ebde421d87d5023b3771..81d02ee3532f109e5bac7709aebb6bfb32cee4cb 100644
--- a/src/libknot/nameserver/name-server.c
+++ b/src/libknot/nameserver/name-server.c
@@ -2605,7 +2605,7 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig)
 
 	// Clean the response structure
 	dbg_ns_verb("Clearing response structure..\n");
-	knot_response_clear(xfr->response, 0);
+	knot_response_clear(xfr->response);
 
 	// increment the packet number
 	++xfr->packet_nr;
@@ -2996,7 +2996,7 @@ static int ns_ixfr(knot_ns_xfr_t *xfr)
 /*----------------------------------------------------------------------------*/
 
 static int knot_ns_prepare_response(knot_packet_t *query, knot_packet_t **resp,
-                                    size_t max_size, int copy_question)
+                                    size_t max_size)
 {
 	assert(max_size >= 500);
 
@@ -3015,7 +3015,7 @@ static int knot_ns_prepare_response(knot_packet_t *query, knot_packet_t **resp,
 		return ret;
 	}
 
-	ret = knot_response_init_from_query(*resp, query, copy_question);
+	ret = knot_response_init_from_query(*resp, query);
 
 	if (ret != KNOT_EOK) {
 		dbg_ns("Failed to init response structure.\n");
@@ -3350,8 +3350,7 @@ int knot_ns_error_response_from_query(const knot_nameserver_t *nameserver,
 	if (query->parsed > KNOT_WIRE_HEADER_SIZE
 	                    + KNOT_WIRE_QUESTION_MIN_SIZE) {
 		// in this case the whole question was parsed, append it
-		size_t question_size = 4 + knot_dname_size(
-		                        knot_packet_qname(query));
+		size_t question_size = knot_packet_question_size(query);
 
 		if (max_size > KNOT_WIRE_HEADER_SIZE + question_size) {
 			/*
@@ -3488,7 +3487,7 @@ int knot_ns_prep_normal_response(knot_nameserver_t *nameserver,
 		resp_max_size = MAX_UDP_PAYLOAD;
 	}
 
-	ret = knot_ns_prepare_response(query, resp, resp_max_size, 1);
+	ret = knot_ns_prepare_response(query, resp, resp_max_size);
 	if (ret != KNOT_EOK) {
 		return KNOT_ERROR;
 	}
@@ -3627,11 +3626,15 @@ int knot_ns_prep_update_response(knot_nameserver_t *nameserver,
 		resp_max_size = MAX_UDP_PAYLOAD;
 	}
 
-	ret = knot_ns_prepare_response(query, resp, resp_max_size, 0);
+	ret = knot_ns_prepare_response(query, resp, resp_max_size);
 	if (ret != KNOT_EOK) {
 		return KNOT_ERROR;
 	}
 
+	/* Trim question for DDNS answer. */
+	knot_packet_set_size(query, KNOT_WIRE_HEADER_SIZE);
+	knot_wire_set_qdcount(query->wireformat, 0);
+
 	dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n",
 	            query->parsed, query->size);
 	dbg_ns_detail("Opt RR: version: %d, payload: %d\n",
@@ -3821,7 +3824,7 @@ dbg_ns_exec(
 int knot_ns_init_xfr_resp(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
 {
 	int ret = KNOT_EOK;
-	knot_packet_t *resp = knot_packet_new();
+	knot_packet_t *resp = knot_packet_new_mm(&xfr->query->mm);
 	if (resp == NULL) {
 		dbg_ns("Failed to create packet structure.\n");
 		/*! \todo xfr->wire is not NULL, will fail on assert! */
@@ -3836,7 +3839,7 @@ int knot_ns_init_xfr_resp(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
 	resp->wireformat = xfr->wire;
 	resp->max_size = xfr->wire_size;
 
-	ret = knot_response_init_from_query(resp, xfr->query, 1);
+	ret = knot_response_init_from_query(resp, xfr->query);
 
 	if (ret != KNOT_EOK) {
 		dbg_ns("Failed to init response structure.\n");
diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c
index 8447489db07203300a7f3cdbcae3148fe1865089..2112290515c227be6c455ff8146a0e789208e05b 100644
--- a/src/libknot/updates/xfr-in.c
+++ b/src/libknot/updates/xfr-in.c
@@ -59,22 +59,10 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype,
 		return KNOT_ERROR;
 	}
 
-	knot_question_t question;
-
-	/* Retain qname until the question is freed. */
-	knot_dname_retain(qname);
-
 	/* Set random query ID. */
 	knot_packet_set_random_id(pkt);
-
-	// this is ugly!!
-	question.qname = (knot_dname_t *)qname;
-	question.qtype = qtype;
-	question.qclass = qclass;
-
-	rc = knot_query_set_question(pkt, &question);
+	rc = knot_query_set_question(pkt, qname, qclass, qtype);
 	if (rc != KNOT_EOK) {
-		knot_dname_release(question.qname);
 		knot_packet_free(&pkt);
 		return KNOT_ERROR;
 	}
@@ -98,7 +86,6 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype,
 	rc = knot_packet_to_wire(pkt, &wire, &wire_size);
 	if (rc != KNOT_EOK) {
 		dbg_xfrin("Failed to write packet to wire.\n");
-		knot_dname_release(question.qname);
 		knot_packet_free(&pkt);
 		return KNOT_ERROR;
 	}
@@ -140,9 +127,6 @@ static int xfrin_create_query(knot_dname_t *qname, uint16_t qtype,
 
 	knot_packet_free(&pkt);
 
-	/* Release qname. */
-	knot_dname_release(question.qname);
-
 	return KNOT_EOK;
 }
 
diff --git a/src/utils/common/exec.c b/src/utils/common/exec.c
index 639a81fc5f962d780afbd166a2748a0580f7689a..38a6482b6f91f7ee795ca4e5c52c941d76822d67 100644
--- a/src/utils/common/exec.c
+++ b/src/utils/common/exec.c
@@ -320,7 +320,7 @@ static void print_section_host(const knot_rrset_t **rrsets,
 }
 
 static void print_error_host(const uint8_t         code,
-                             const knot_question_t *question)
+                             const knot_packet_t   *packet)
 {
 	const char *rcode_str = "NULL";
 	char type[32] = "NULL";
@@ -328,12 +328,12 @@ static void print_error_host(const uint8_t         code,
 
 	knot_lookup_table_t *rcode;
 
-	owner = knot_dname_to_str(question->qname);
+	owner = knot_dname_to_str(knot_packet_qname(packet));
 	rcode = knot_lookup_by_id(knot_rcode_names, code);
 	if (rcode != NULL) {
 		rcode_str = rcode->name;
 	}
-	knot_rrtype_to_string(question->qtype, type, sizeof(type));
+	knot_rrtype_to_string(knot_packet_qtype(packet), type, sizeof(type));
 
 	if (code == KNOT_RCODE_NOERROR) {
 		printf("Host %s has no %s record\n", owner, type);
@@ -365,7 +365,7 @@ knot_packet_t* create_empty_packet(const size_t max_size)
 	return packet;
 }
 
-void print_header_xfr(const knot_question_t *question, const style_t  *style)
+void print_header_xfr(const knot_packet_t *packet, const style_t  *style)
 {
 	if (style == NULL) {
 		DBG_NULL;
@@ -374,7 +374,7 @@ void print_header_xfr(const knot_question_t *question, const style_t  *style)
 
 	char xfr[16] = "AXFR";
 
-	switch (question->qtype) {
+	switch (knot_packet_qtype(packet)) {
 	case KNOT_RRTYPE_AXFR:
 		break;
 	case KNOT_RRTYPE_IXFR:
@@ -385,7 +385,7 @@ void print_header_xfr(const knot_question_t *question, const style_t  *style)
 	}
 
 	if (style->show_header) {
-		char *owner = knot_dname_to_str(question->qname);
+		char *owner = knot_dname_to_str(knot_packet_qname(packet));
 		if (owner != NULL) {
 			printf("\n;; %s for %s\n", xfr, owner);
 			free(owner);
@@ -487,15 +487,15 @@ void print_packet(const knot_packet_t *packet,
 			print_section_host(packet->answer, ancount,
 			                   style);
 		} else {
-			print_error_host(rcode, &packet->question);
+			print_error_host(rcode, packet);
 		}
 		break;
 	case FORMAT_NSUPDATE:
 		if (style->show_question && qdcount > 0) {
 			printf("\n;; ZONE SECTION:\n;; ");
-			print_section_question(packet->question.qname,
-			                       packet->question.qclass,
-			                       packet->question.qtype,
+			print_section_question(knot_packet_qname(packet),
+			                       knot_packet_qclass(packet),
+			                       knot_packet_qtype(packet),
 			                       style);
 		}
 
@@ -523,9 +523,9 @@ void print_packet(const knot_packet_t *packet,
 	case FORMAT_FULL:
 		if (style->show_question && qdcount > 0) {
 			printf("\n;; QUESTION SECTION:\n;; ");
-			print_section_question(packet->question.qname,
-			                       packet->question.qclass,
-			                       packet->question.qtype,
+			print_section_question(knot_packet_qname(packet),
+			                       knot_packet_qclass(packet),
+			                       knot_packet_qtype(packet),
 			                       style);
 		}
 
diff --git a/src/utils/common/exec.h b/src/utils/common/exec.h
index 33b9ed428fcb4ec1690b6b31ad4e58e20d0d1ef3..00d969c0df5d01298643738489426d73b04032e9 100644
--- a/src/utils/common/exec.h
+++ b/src/utils/common/exec.h
@@ -52,10 +52,10 @@ knot_packet_t* create_empty_packet(const size_t                      max_size);
 /*!
  * \brief Prints information header for transfer.
  *
- * \param question	Packet question section.
+ * \param packet	Parsed packet.
  * \param style		Style of the output.
  */
-void print_header_xfr(const knot_question_t *question, const style_t *style);
+void print_header_xfr(const knot_packet_t *packet, const style_t *style);
 
 /*!
  * \brief Prints answer section for 1 transfer message.
diff --git a/src/utils/dig/dig_exec.c b/src/utils/dig/dig_exec.c
index 3a46a7cf3a3e5b9683b6bdf0faf194dd9534a16c..c3fa9c3a16a084591c27469caf49e8da0ee49e03 100644
--- a/src/utils/dig/dig_exec.c
+++ b/src/utils/dig/dig_exec.c
@@ -35,7 +35,6 @@ static knot_packet_t* create_query_packet(const query_t *query,
                                           uint8_t       **data,
                                           size_t        *data_len)
 {
-	knot_question_t q;
 	knot_packet_t   *packet;
 
 	// Set packet buffer size.
@@ -80,20 +79,19 @@ static knot_packet_t* create_query_packet(const query_t *query,
 		knot_wire_set_cd(packet->wireformat);
 	}
 
-	// Fill auxiliary question structure.
-	q.qclass = query->class_num;
-	q.qtype = query->type_num;
-	q.qname = knot_dname_new_from_str(query->owner, strlen(query->owner), 0);
-	if (q.qname == NULL) {
+	// Create QNAME from string.
+	knot_dname_t *qname = knot_dname_new_from_str(query->owner,
+	                                              strlen(query->owner), 0);
+	if (qname == NULL) {
 		knot_packet_free(&packet);
 		return NULL;
 	}
 
 	// Set packet question.
-	if (knot_query_set_question(packet, &q) != KNOT_EOK) {
-		// It's necessary to release q.qname by hand as it isn't
-		// connected with the packet yet.
-		knot_dname_release(q.qname);
+	int ret = knot_query_set_question(packet, qname,
+	                                  query->class_num, query->type_num);
+	if (ret != KNOT_EOK) {
+		knot_dname_free(&qname);
 		knot_packet_free(&packet);
 		return NULL;
 	}
@@ -103,13 +101,13 @@ static knot_packet_t* create_query_packet(const query_t *query,
 		// SOA rdata in wireformat.
 		uint8_t wire[22] = { 0x0 };
 		size_t  pos = 0;
-		int     ret;
 
 		// Create rrset with SOA record.
-		knot_rrset_t *soa = knot_rrset_new(q.qname,
+		knot_rrset_t *soa = knot_rrset_new(qname,
 		                                   KNOT_RRTYPE_SOA,
 		                                   query->class_num,
 		                                   0);
+		knot_dname_free(&qname); /* Won't be needed anymore. */
 		if (soa == NULL) {
 			knot_packet_free(&packet);
 			return NULL;
@@ -222,11 +220,11 @@ static void check_reply_question(const knot_packet_t *reply,
 		return;
 	}
 
-	int name_diff = knot_dname_compare_cs(reply->question.qname,
-	                                      query->question.qname);
+	int name_diff = knot_dname_compare_cs(knot_packet_qname(reply),
+	                                      knot_packet_qname(query));
 
-	if (reply->question.qclass != query->question.qclass ||
-	    reply->question.qtype  != query->question.qtype ||
+	if (knot_packet_qclass(reply) != knot_packet_qclass(query) ||
+	    knot_packet_qtype(reply)  != knot_packet_qtype(query) ||
 	    name_diff != 0) {
 		WARN("query/response question sections are different\n");
 		return;
@@ -527,7 +525,7 @@ static int process_packet_xfr(const knot_packet_t     *query,
 	}
 
 	// Print leading transfer information.
-	print_header_xfr(&query->question, style);
+	print_header_xfr(query, style);
 
 	// Loop over reply messages unless first and last SOA serials differ.
 	while (true) {
diff --git a/src/utils/nsupdate/nsupdate_exec.c b/src/utils/nsupdate/nsupdate_exec.c
index 34e8cd73c03fcb784da8a855b532e838e39afd4b..53f26fe611fa3380974a6775c09109635724d6ca 100644
--- a/src/utils/nsupdate/nsupdate_exec.c
+++ b/src/utils/nsupdate/nsupdate_exec.c
@@ -301,17 +301,18 @@ static int pkt_append(nsupdate_params_t *p, int sect)
 {
 	/* Check packet state first. */
 	int ret = KNOT_EOK;
+	knot_dname_t * qname = NULL;
 	scanner_t *s = p->rrp;
 	if (!p->pkt) {
 		p->pkt = create_empty_packet(MAX_PACKET_SIZE);
-		knot_question_t q;
-		q.qclass = p->class_num;
-		q.qtype = p->type_num;
-		q.qname = knot_dname_new_from_nonfqdn_str(p->zone, strlen(p->zone), NULL);
-		ret = knot_query_set_question(p->pkt, &q);
-		if (ret != KNOT_EOK) {
+		qname = knot_dname_new_from_nonfqdn_str(p->zone,
+		                                        strlen(p->zone),
+		                                        NULL);
+		ret = knot_query_set_question(p->pkt, qname, p->class_num, p->type_num);
+		knot_dname_free(&qname);
+		if (ret != KNOT_EOK)
 			return ret;
-		}
+
 		knot_query_set_opcode(p->pkt, KNOT_OPCODE_UPDATE);
 	}
 
@@ -728,8 +729,6 @@ int cmd_send(const char* lp, nsupdate_params_t *params)
 	}
 
 	/* Clear sent packet. */
-	knot_question_t *q = knot_packet_question(params->pkt);
-	knot_dname_release(q->qname);
 	knot_packet_free_rrsets(params->pkt);
 	knot_packet_free(&params->pkt);