diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c
index 491aba4e8a5d14253f0c1f6d928ee2d798886553..b2d729933d29c308af55e1d36ab80d79e204f656 100644
--- a/src/knot/ctl/remote.c
+++ b/src/knot/ctl/remote.c
@@ -119,7 +119,7 @@ static int remote_zone_refresh(server_t *server, const zone_t *zone)
 		return KNOT_EINVAL;
 	}
 
-	zones_schedule_refresh((zone_t *)zone, knot_random_uint32_t() % 1000);
+	zones_schedule_refresh((zone_t *)zone, REFRESH_NOW);
 
 	return KNOT_EOK;
 }
@@ -131,7 +131,7 @@ static int remote_zone_flush(server_t *server, const zone_t *zone)
 		return KNOT_EINVAL;
 	}
 
-	zones_schedule_zonefile_sync((zone_t *)zone, knot_random_uint32_t() % 1000);
+	zones_schedule_zonefile_sync((zone_t *)zone, REFRESH_NOW);
 
 	return KNOT_EOK;
 }
@@ -327,7 +327,7 @@ static int remote_c_refresh(server_t *s, remote_cmdargs_t* a)
 	dbg_server("remote: %s\n", __func__);
 	if (a->argc == 0) {
 		dbg_server_verb("remote: refreshing all zones\n");
-		knot_zonedb_foreach(s->zone_db, zones_schedule_refresh, 0);
+		knot_zonedb_foreach(s->zone_db, zones_schedule_refresh, REFRESH_NOW);
 		return KNOT_EOK;
 	}
 
diff --git a/src/knot/nameserver/update.c b/src/knot/nameserver/update.c
index e5a1dfe110f3253a9393e6256151f62aebc05ece..b14e410de9fdcccdac9e88a4921cc5c0e5eb27be 100644
--- a/src/knot/nameserver/update.c
+++ b/src/knot/nameserver/update.c
@@ -9,6 +9,7 @@
 #include "knot/updates/ddns.h"
 #include "common/descriptor.h"
 #include "knot/server/zones.h"
+#include "libknot/tsig-op.h"
 
 /* Forward decls. */
 static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query,
@@ -46,19 +47,32 @@ static int update_forward(knot_pkt_t *pkt, struct query_data *qdata)
 	rq->packet_nr = knot_wire_get_id(query->wire);
 
 	/* Duplicate query to keep it in memory during forwarding. */
-	rq->query = knot_pkt_new(NULL, query->size, NULL);
-	if (!rq->query) {
+	rq->query = knot_pkt_new(NULL, query->max_size, NULL);
+	if (rq->query == NULL) {
 		xfr_task_free(rq);
 		return NS_PROC_FAIL;
+	} else {
+		memcpy(rq->query->wire, query->wire, query->size);
+		rq->query->size = query->size;
+	}
+
+	/* Copy TSIG. */
+	int ret = KNOT_EOK;
+	if (query->tsig_rr) {
+		ret = knot_tsig_append(rq->query->wire, &rq->query->size,
+		                       rq->query->max_size, query->tsig_rr);
+		if (ret != KNOT_EOK) {
+			xfr_task_free(rq);
+			return NS_PROC_FAIL;
+		}
 	}
-	memcpy(rq->query->wire, query->wire, query->size);
-	rq->query->size = query->size;
 
 	/* Retain pointer to zone and issue. */
 	xfrhandler_t *xfr = qdata->param->server->xfr;
-	int ret = xfr_enqueue(xfr, rq);
+	ret = xfr_enqueue(xfr, rq);
 	if (ret != KNOT_EOK) {
 		xfr_task_free(rq);
+		return NS_PROC_FAIL;
 	}
 
 	/* No immediate response. */
diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c
index 4e4a171a75e019784340cf7a01ada025a2fdfe8e..825daf3811fad09bca0f6fad20f9b6cd269e6b26 100644
--- a/src/knot/server/notify.c
+++ b/src/knot/server/notify.c
@@ -70,19 +70,6 @@ int notify_process_response(knot_pkt_t *notify, int msgid)
 	return KNOT_EOK;
 }
 
-static int notify_reschedule(const zone_t *zone)
-{
-	dbg_ns("%s(%p)\n", __func__, zone);
-	if (zone == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	/* Incoming NOTIFY expires REFRESH timer and renews EXPIRE timer. */
-	zones_schedule_refresh((zone_t *)zone, 0);
-
-	return KNOT_EOK;
-}
-
 /* NOTIFY-specific logging (internal, expects 'qdata' variable set). */
 #define NOTIFY_LOG(severity, msg...) \
 	QUERY_LOG(severity, qdata, "NOTIFY", msg)
@@ -117,7 +104,9 @@ int internet_notify(knot_pkt_t *pkt, struct query_data *qdata)
 	}
 
 	int next_state = NS_PROC_FAIL;
-	int ret = notify_reschedule(qdata->zone);
+
+	/* Incoming NOTIFY expires REFRESH timer and renews EXPIRE timer. */
+	int ret =  zones_schedule_refresh((zone_t *)qdata->zone, REFRESH_NOW);
 
 	/* Format resulting log message. */
 	if (ret != KNOT_EOK) {
diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c
index 78f50515f7d22ec047fc1e3be3937b7a48727e14..4fdfb73f172a443e84d398aea4c4cac1eb3f32cb 100644
--- a/src/knot/server/xfr-handler.c
+++ b/src/knot/server/xfr-handler.c
@@ -137,37 +137,45 @@ static int parse_packet(knot_pkt_t *packet, knot_pkt_type_t *type)
 }
 
 /*! \brief Create forwarded query. */
-static int forward_packet(const knot_pkt_t *query, knot_pkt_t *pkt)
+static int forward_packet(knot_ns_xfr_t *data, knot_pkt_t *pkt)
 {
-	/* Forward UPDATE query:
-	 * assign a new packet id
-	 */
+	knot_pkt_t *query = data->query;
 	memcpy(pkt->wire, query->wire, query->size);
 	pkt->size = query->size;
+
+	/* Assign new message id. */
+	data->packet_nr = knot_wire_get_id(pkt->wire);
 	knot_wire_set_id(pkt->wire, knot_random_uint16_t());
 
 	return KNOT_EOK;
 }
 
 /*! \brief Forwarded packet response. */
-int forward_packet_response(knot_ns_xfr_t *data, uint8_t *rwire, size_t *rsize)
+static int forward_packet_response(knot_ns_xfr_t *data, knot_pkt_t *pkt)
 {
-	/* Processing of a forwarded response:
-	 * change packet id
-	 */
+	/* Restore message id. */
+	knot_wire_set_id(pkt->wire, (uint16_t)data->packet_nr);
+
+	/* Restore TSIG. */
 	int ret = KNOT_EOK;
-	knot_wire_set_id(rwire, (uint16_t)data->packet_nr);
+	if (pkt->tsig_rr) {
+		ret = knot_tsig_append(pkt->wire, &pkt->size, pkt->max_size,
+		                       pkt->tsig_rr);
+	}
 
 	/* Forward the response. */
-	ret = data->send(data->fwd_src_fd, &data->fwd_addr, rwire, *rsize);
-	if (ret != *rsize) {
-		ret = KNOT_ECONN;
-	} else {
-		ret = KNOT_EOK;
+	if (ret == KNOT_EOK) {
+		ret = data->send(data->fwd_src_fd, &data->fwd_addr,
+		                 pkt->wire, pkt->size);
+		if (ret != pkt->size) {
+			ret = KNOT_ECONN;
+		} else {
+			ret = KNOT_EOK;
+		}
 	}
 
-	/* As it is a response, do not reply back. */
-	*rsize = 0;
+	/* Invalidate response => do not reply to master. */
+	pkt->size = 0;
 	return ret;
 }
 
@@ -416,7 +424,7 @@ static int xfr_task_start(knot_ns_xfr_t *rq)
 		ret = notify_create_request(zone, pkt);
 		break;
 	case XFR_TYPE_FORWARD:
-		ret = forward_packet(rq->query, pkt);
+		ret = forward_packet(rq, pkt);
 		break;
 	default:
 		ret = KNOT_EINVAL;
@@ -719,17 +727,16 @@ static int xfr_task_resp(xfrhandler_t *xfr, knot_ns_xfr_t *rq)
 	}
 
 	/* Process response. */
-	size_t rlen = rq->wire_size;
 	switch(rt) {
 	case KNOT_RESPONSE_NORMAL:
 		ret = zones_process_response(xfr->server, rq->packet_nr, &rq->addr,
-		                             re, rq->wire, &rlen);
+		                             re);
 		break;
 	case KNOT_RESPONSE_NOTIFY:
 		ret = notify_process_response(re, rq->packet_nr);
 		break;
 	case KNOT_RESPONSE_UPDATE:
-		ret = forward_packet_response(rq, rq->wire, &rlen);
+		ret = forward_packet_response(rq, re);
 		if (ret == KNOT_EOK) {
 			log_zone_info("%s Forwarded response.\n", rq->msg);
 		}
diff --git a/src/knot/server/zone-load.c b/src/knot/server/zone-load.c
index 9799a3a7b1231e1a31a434d9e1e10eecd35fa9cd..f6b64ac86f5c728cd5d80cf7e9d67cbddb236d71 100644
--- a/src/knot/server/zone-load.c
+++ b/src/knot/server/zone-load.c
@@ -291,6 +291,8 @@ fail:
 			new_zone->contents = NULL;
 		}
 
+		/* Disconnect config, caller is responsible for it. */
+		new_zone->conf = NULL;
 		zone_free(&new_zone);
 	}
 
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index 212ae835a3a5105a163c110d768a14611fce4c01..7914cea8a758e55c14d7235e11a749dfc31c9dd3 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -1036,17 +1036,12 @@ int zones_zonefile_sync(zone_t *zone, journal_t *journal)
 int zones_process_response(server_t *server,
                            int exp_msgid,
                            sockaddr_t *from,
-                           knot_pkt_t *packet, uint8_t *response_wire,
-                           size_t *rsize)
+                           knot_pkt_t *packet)
 {
-	if (!packet || !rsize || server == NULL || from == NULL ||
-	    response_wire == NULL) {
+	if (!packet || server == NULL || from == NULL) {
 		return KNOT_EINVAL;
 	}
 
-	/* Declare no response. */
-	*rsize = 0;
-
 	/* Handle SOA query response, cancel EXPIRE timer
 	 * and start AXFR transfer if needed.
 	 * Reset REFRESH timer on finish.
@@ -1995,7 +1990,7 @@ int zones_do_diff_and_sign(const conf_zone_t *z, zone_t *zone, zone_t *old_zone,
 		/* Even if there's nothing to create the diff from
 		 * we can still sign the zone - inconsistencies may happen. */
 		// TODO consider returning straight away when serial did not change
-		if (ret != KNOT_EOK && ret != KNOT_ENODIFF) {
+		if (ret != KNOT_EOK && ret != KNOT_ENODIFF && ret != KNOT_ERANGE) {
 			knot_changesets_free(&diff_chs);
 			rcu_read_unlock();
 			return ret;
diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h
index 2786260b7bc6e261f9011ea5f1a04b5cb2a72d63..801c6fd7c76ecd7e71cc40ffeb9dd10b1afa8886 100644
--- a/src/knot/server/zones.h
+++ b/src/knot/server/zones.h
@@ -45,9 +45,9 @@
 #define AXFR_BOOTSTRAP_RETRY (30*1000) /*!< Interval between AXFR BS retries. */
 #define AXFR_RETRY_MAXTIME (10*60*1000) /*!< Maximum interval 10mins */
 
-enum {
-	REFRESH_DEFAULT = -1 /* Use time value from zone structure. */
-};
+/* Timer special values. */
+#define REFRESH_DEFAULT -1 /* Use time value from zone structure. */
+#define REFRESH_NOW (knot_random_uint16_t() % 1000) /* Now, but with jitter. */
 
 /*!
  * \brief Sync zone data back to text zonefile.
@@ -73,9 +73,6 @@ int zones_zonefile_sync(zone_t *zone, journal_t *journal);
  * \param server Name server structure to provide the needed data.
  * \param from Address of the response sender.
  * \param packet Parsed response packet.
- * \param response_wire Place for the response in wire format.
- * \param rsize Input: maximum acceptable size of the response. Output: real
- *              size of the response.
  *
  * \retval KNOT_EOK if a valid response was created.
  * \retval KNOT_EINVAL on invalid parameters or packet.
@@ -84,8 +81,7 @@ int zones_zonefile_sync(zone_t *zone, journal_t *journal);
 int zones_process_response(server_t *server,
                            int exp_msgid,
                            sockaddr_t *from,
-                           knot_pkt_t *packet, uint8_t *response_wire,
-                           size_t *rsize);
+                           knot_pkt_t *packet);
 
 /*!
  * \brief Decides what type of transfer should be used to update the given zone.
diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c
index 4f9bf8032c1dd81c5cf8c9a098176968e9ef9339..8cd01161ab791e8aab51bd876fc8dc64e9865d74 100644
--- a/src/knot/zone/zone.c
+++ b/src/knot/zone/zone.c
@@ -130,7 +130,7 @@ int zone_timers_thaw(zone_t *zone)
 	zones_schedule_zonefile_sync(zone, zone->conf->dbsync_timeout);
 
 	/* Schedule REFRESH. */
-	zones_schedule_refresh(zone, 0);
+	zones_schedule_refresh(zone, REFRESH_NOW);
 
 	return KNOT_EOK;
 }
diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c
index 59c40b5c6c5b792ba3945e062d62cd506be43a83..72dbc28fb2697dc1bc1c1e4cd9d956989494a25a 100644
--- a/src/libknot/tsig-op.c
+++ b/src/libknot/tsig-op.c
@@ -846,27 +846,35 @@ int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
 	/* Set other len. */
 	tsig_rdata_set_other_data(tmp_tsig, 0, 0);
 
+
+	/* Append TSIG RR. */
+	int ret = knot_tsig_append(msg, msg_len, msg_max_len, tsig_rr);
+
+	/* key_name already referenced in RRSet, no need to free separately. */
+	knot_rrset_deep_free(&tmp_tsig, 1);
+
+	return ret;
+}
+
+int knot_tsig_append(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+                     const knot_rrset_t *tsig_rr)
+{
 	size_t tsig_wire_len = 0;
 	uint16_t rr_count = 0;
 
 	/* Write RRSet to wire */
 	int ret = KNOT_ERROR;
-	ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
+	ret = knot_rrset_to_wire(tsig_rr, msg + *msg_len,
 	                         &tsig_wire_len, msg_max_len - *msg_len,
 	                         &rr_count, NULL);
 	if (ret != KNOT_EOK) {
 		dbg_tsig("TSIG: rrset_to_wire = %s\n", knot_strerror(ret));
-		knot_rrset_deep_free(&tmp_tsig, 1, NULL);
 		return ret;
 	}
 
-	/* key_name already referenced in RRSet, no need to free separately. */
-	knot_rrset_deep_free(&tmp_tsig, 1, NULL);
-
 	*msg_len += tsig_wire_len;
 
-	uint16_t arcount = knot_wire_get_arcount(msg);
-	knot_wire_set_arcount(msg, ++arcount);
+	knot_wire_set_arcount(msg, knot_wire_get_arcount(msg) + 1);
 
 	return KNOT_EOK;
 }
diff --git a/src/libknot/tsig-op.h b/src/libknot/tsig-op.h
index 9351fc2e2079ccd9acc1ee6b98b7914481d29cbd..ce627b5c94f11f17b8f3fc54119108b411896906 100644
--- a/src/libknot/tsig-op.h
+++ b/src/libknot/tsig-op.h
@@ -164,6 +164,10 @@ int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr,
 int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
                   uint16_t tsig_rcode, const knot_rrset_t *tsig_rr);
 
+/*! \brief Append TSIG RR to message. */
+int knot_tsig_append(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+                     const knot_rrset_t *tsig_rr);
+
 /*! \brief Return true if the TSIG RCODE allows signing the packet. */
 static inline bool knot_tsig_can_sign(uint16_t tsig_rcode) {
 	return (tsig_rcode == KNOT_RCODE_NOERROR || tsig_rcode == KNOT_RCODE_BADTIME);
diff --git a/tests-extra/tests/records/badrecord/data/badrecord.zone b/tests-extra/tests/records/badrecord/data/badrecord.zone
new file mode 100644
index 0000000000000000000000000000000000000000..dec64cdddc72dc118514f053f6d77a4897ef70e5
--- /dev/null
+++ b/tests-extra/tests/records/badrecord/data/badrecord.zone
@@ -0,0 +1,15 @@
+$ORIGIN badrecord.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 2010111213 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+	MX	10 mail
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+dns3 ; Unfinished record
diff --git a/tests-extra/tests/records/badrecord/test.py b/tests-extra/tests/records/badrecord/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c271d3574d8282fc87dbc45effa074796237af9
--- /dev/null
+++ b/tests-extra/tests/records/badrecord/test.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+
+''' Test for loading badly formed record '''
+
+from dnstest.test import Test
+
+t = Test()
+
+master = t.server("knot")
+
+zone = t.zone("badrecord.", "badrecord.zone", storage=".")
+
+t.link(zone, master)
+
+t.start()
+
+# Check if the server is answering and zone _isn't_ loaded
+resp = master.dig("badrecord.", "SOA", udp=True)
+resp.check(rcode="REFUSED")
+
+# Stop master.
+master.stop()
+
+t.end()
diff --git a/tests-extra/tests/zone/notexists/test.py b/tests-extra/tests/zone/notexists/test.py
index 74de6a41927e15fdce5008c80a1e4de9b1caf2a8..74740c40bce7c3ec52ca099b9eb230df1aa8c6c9 100644
--- a/tests-extra/tests/zone/notexists/test.py
+++ b/tests-extra/tests/zone/notexists/test.py
@@ -14,6 +14,14 @@ t.link(zones, master)
 
 t.start()
 
+# Check if the server is answering and zone _isn't_ loaded
+resp = master.dig("notexist.", "SOA", udp=True)
+resp.check(rcode="REFUSED")
+
+# The other zone should answer without problem
+resp = master.dig("wild.", "SOA", udp=True)
+resp.check(rcode="NOERROR")
+
 # Stop master.
 master.stop()
 
diff --git a/tests-extra/tests/zone/reload/data/serial.zone b/tests-extra/tests/zone/reload/data/serial.zone
new file mode 100644
index 0000000000000000000000000000000000000000..e1bdba4cb1aa9f93b9f3f9575ed435b6656d5e2c
--- /dev/null
+++ b/tests-extra/tests/zone/reload/data/serial.zone
@@ -0,0 +1,14 @@
+$ORIGIN serial.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 2010111213 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+new-record0 A 1.2.3.4 ; RR tagging the zone version (independent on serial)
diff --git a/tests-extra/tests/zone/reload/data/serial.zone.1 b/tests-extra/tests/zone/reload/data/serial.zone.1
new file mode 100644
index 0000000000000000000000000000000000000000..56f8802391a0ee2bb4208ce89f464901ce958228
--- /dev/null
+++ b/tests-extra/tests/zone/reload/data/serial.zone.1
@@ -0,0 +1,14 @@
+$ORIGIN serial.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 2010111214 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+new-record1 A 1.2.3.4 ; RR tagging the zone version (independent on serial)
diff --git a/tests-extra/tests/zone/reload/data/serial.zone.2 b/tests-extra/tests/zone/reload/data/serial.zone.2
new file mode 100644
index 0000000000000000000000000000000000000000..5f4c25fca795b83b4460c2d69407f74c04583a17
--- /dev/null
+++ b/tests-extra/tests/zone/reload/data/serial.zone.2
@@ -0,0 +1,14 @@
+$ORIGIN serial.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 2010111214 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+new-record2 A 1.2.3.4 ; RR tagging the zone version (independent on serial)
diff --git a/tests-extra/tests/zone/reload/data/serial.zone.3 b/tests-extra/tests/zone/reload/data/serial.zone.3
new file mode 100644
index 0000000000000000000000000000000000000000..ecc42acd0d28ffb3f32145ae44c62ee5e06d113c
--- /dev/null
+++ b/tests-extra/tests/zone/reload/data/serial.zone.3
@@ -0,0 +1,14 @@
+$ORIGIN serial.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 2010111212 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+new-record3 A 1.2.3.4 ; RR tagging the zone version (independent on serial)
diff --git a/tests-extra/tests/zone/reload/data/serial.zone.4 b/tests-extra/tests/zone/reload/data/serial.zone.4
new file mode 100644
index 0000000000000000000000000000000000000000..31f98ee00677d57fe2d6228466d301d487fbc85e
--- /dev/null
+++ b/tests-extra/tests/zone/reload/data/serial.zone.4
@@ -0,0 +1,14 @@
+$ORIGIN serial.
+$TTL 3600
+
+@	SOA	dns1 hostmaster 2010111212 10800 3600 1209600 7200
+	NS	dns1
+	NS	dns2
+
+dns1	A	192.0.2.1
+	AAAA	2001:DB8::1
+
+dns2	A	192.0.2.2
+	AAAA	2001:DB8::2
+
+new-record4 A 1.2.3.4 ; RR tagging the zone version (independent on serial)
diff --git a/tests-extra/tests/zone/reload/test.py b/tests-extra/tests/zone/reload/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..3c09103307c2d9a3a5bbf4bc053db227181ec166
--- /dev/null
+++ b/tests-extra/tests/zone/reload/test.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+
+'''Test for reload of a changed zone (serial up, nochange, serial down). '''
+
+from dnstest.test import Test
+from dnstest.utils import set_err, detail_log
+
+t = Test()
+
+master = t.server("knot")
+
+# Zone setup
+zone = t.zone("serial.", storage = ".")
+
+t.link(zone, master, ixfr = True)
+
+t.start()
+
+# Load zones
+serial = master.zone_wait(zone)
+
+def reload_zone(serial, version):
+    master.update_zonefile(zone, version)
+    master.reload()
+    new_serial = master.zone_wait(zone)
+    if new_serial != serial:
+        set_err("SOA MISMATCH")
+        detail_log("!Zone '%s' SOA serial %s != %s" % (zone[0].name, new_serial, serial))
+        return
+    resp = master.dig("new-record%d.%s" % (version, zone[0].name), "A")
+    resp.check(rcode="NOERROR")
+
+# Zone changes, serial increases (create changeset)
+version = 1 
+serial = serial + 1
+reload_zone(serial, version)
+
+# Zone changes, serial doesn't change (no new changeset)
+version += 1
+reload_zone(serial, version)
+
+# Zone changes, serial jumps out-of-range (journal is not applicable)
+version += 1
+serial = serial - 2 
+reload_zone(serial, version)
+
+# Stop master.
+master.stop()
+
+t.end()
diff --git a/tests-extra/tools/dnstest/keys.py b/tests-extra/tools/dnstest/keys.py
index 532129fcfe79e18d23231205602bda65c96673d3..485eb0eb0af0254175885af131279ff712dec0de 100644
--- a/tests-extra/tools/dnstest/keys.py
+++ b/tests-extra/tools/dnstest/keys.py
@@ -61,14 +61,14 @@ class Tsig(object):
 
         # TSIG preparation for pythondns utils.
         if self.alg == "hmac-md5":
-            alg = "hmac-md5.sig-alg.reg.int"
+            _alg = "hmac-md5.sig-alg.reg.int"
         else:
-            alg = self.alg
+            _alg = self.alg
 
-        key = dns.tsigkeyring.from_text({
+        _key = dns.tsigkeyring.from_text({
             self.name: self.key
         })
-        self.key_params = dict(keyname=self.name, keyalgorithm=alg, keyring=key)
+        self.key_params = dict(keyname=self.name, keyalgorithm=_alg, keyring=_key)
 
     def dump(self, filename):
         s = dnstest.server.BindConf()