diff --git a/src/knot/server/net.c b/src/knot/server/net.c
index c1d061a8104a7ab641ba994cfec4bc6de7e20b41..5e2c8d63367a1b5702dff4b2c49f877d4dd3a90e 100644
--- a/src/knot/server/net.c
+++ b/src/knot/server/net.c
@@ -81,11 +81,6 @@ int net_bound_socket(int type, const struct sockaddr_storage *ss)
 	int flag = 1;
 	(void) setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
 
-	/* Reuse port if available. */
-#if defined(SO_REUSEPORT)
-	(void) setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag));
-#endif
-
 	/* Unlink UNIX socket if exists. */
 	if (ss->ss_family == AF_UNIX) {
 		unlink(addr_str);
diff --git a/src/knot/server/server.c b/src/knot/server/server.c
index b9b3382a06b0be2c08d84cefd33f26652f9e33a3..4a0a0734408b0f132c0ad4b949f7f8d2ecf944d8 100644
--- a/src/knot/server/server.c
+++ b/src/knot/server/server.c
@@ -116,16 +116,12 @@ static int server_init_iface(iface_t *new_if, conf_iface_t *cfg_if)
 	char addr_str[SOCKADDR_STRLEN] = {0};
 	sockaddr_tostr(&cfg_if->addr, addr_str, sizeof(addr_str));
 
-#if defined(SO_REUSEPORT)
-	/* Each thread binds own socket. */
-	int sock = -1;
-#else
 	/* Create bound UDP socket. */
 	int sock = net_bound_socket(SOCK_DGRAM, &cfg_if->addr);
 	if (sock < 0) {
 		return sock;
 	}
-#endif
+
 	new_if->fd[IO_UDP] = sock;
 
 	/* Create bound TCP socket. */
@@ -615,15 +611,26 @@ int server_update_zones(const struct conf_t *conf, void *data)
 {
 	server_t *server = (server_t *)data;
 
+	/* Prevent new events on zones waiting to be replaced. */
+	if (server->zone_db) {
+		knot_zonedb_foreach(server->zone_db, zone_events_freeze);
+	}
+
+	/* Finish operations already in the queue. */
+	worker_pool_wait(server->workers);
+
+	/* Reload zone database and free old zones. */
 	int ret = zonedb_reload(conf, server);
-	if (ret != KNOT_EOK) {
-		return ret;
+
+	/* Plan events on new zones. */
+	if (server->zone_db) {
+		knot_zonedb_foreach(server->zone_db, zone_events_start);
 	}
 
 	/* Trim extra heap. */
 	mem_trim();
 
-	return KNOT_EOK;
+	return ret;
 }
 
 ref_t *server_set_ifaces(server_t *s, fdset_t *fds, int type)
diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c
index e0f8701035bc75bf0fed367d03de3aaf7a86ab2c..12dbf9269b8dd6c633c4bd0f164437b0f5c9fcb7 100644
--- a/src/knot/server/udp-handler.c
+++ b/src/knot/server/udp-handler.c
@@ -456,28 +456,33 @@ int udp_send_msg(int fd, const uint8_t *msg, size_t msglen, struct sockaddr *add
 	return ret;
 }
 
-static void unbind_ifaces(ifacelist_t *ifaces, fd_set *set, int maxfd)
+/*! \brief Release the reference on the interface list and clear watched fdset. */
+static void forget_ifaces(ifacelist_t *ifaces, fd_set *set, int maxfd)
 {
 	ref_release((ref_t *)ifaces);
-#if defined(SO_REUSEPORT)
-	for (int fd = 0; fd <= maxfd; ++fd) {
-		if (FD_ISSET(fd, set)) {
-			close(fd);
-		}
-	}
-#endif
 	FD_ZERO(set);
 }
 
-static int bind_iface(iface_t *iface, fd_set *set)
+/*! \brief Add interface sockets to the watched fdset. */
+static int track_ifaces(ifacelist_t *ifaces, fd_set *set, int *maxfd, int *minfd)
 {
-#if defined(SO_REUSEPORT)
-	int fd = net_bound_socket(SOCK_DGRAM, &iface->addr);
-#else
-	int fd = iface->fd[IO_UDP];
-#endif
-	FD_SET(fd, set);
-	return fd;
+	FD_ZERO(set);
+	*maxfd = -1;
+	*minfd = 0;
+
+	if (ifaces == NULL) {
+		return KNOT_EINVAL;
+	}
+
+	iface_t *iface = NULL;
+	WALK_LIST(iface, ifaces->l) {
+		int fd = iface->fd[IO_UDP];
+		*maxfd = MAX(fd, *maxfd);
+		*minfd = MIN(fd, *minfd);
+		FD_SET(fd, set);
+	}
+
+	return KNOT_EOK;
 }
 
 int udp_master(dthread_t *thread)
@@ -532,18 +537,9 @@ int udp_master(dthread_t *thread)
 			udp.thread_id = handler->thread_id[thr_id];
 
 			rcu_read_lock();
-			unbind_ifaces(ref, &fds, maxfd);
-			maxfd = 0;
-			minfd = INT_MAX;
+			forget_ifaces(ref, &fds, maxfd);
 			ref = handler->server->ifaces;
-			if (ref) {
-				iface_t *i = NULL;
-				WALK_LIST(i, ref->l) {
-					int fd = bind_iface(i, &fds);
-					maxfd = MAX(fd, maxfd);
-					minfd = MIN(fd, minfd);
-				}
-			}
+			track_ifaces(ref, &fds, &maxfd, &minfd);
 			rcu_read_unlock();
 		}
 
@@ -575,7 +571,7 @@ int udp_master(dthread_t *thread)
 	}
 
 	_udp_deinit(rq);
-	unbind_ifaces(ref, &fds, maxfd);
+	forget_ifaces(ref, &fds, maxfd);
 	mp_delete(udp.query_ctx.mm.ctx);
 	return KNOT_EOK;
 }
diff --git a/src/knot/worker/pool.c b/src/knot/worker/pool.c
index d6d0cf046c1df9510943b4682ffe9bd7c9b6e2e9..42ff57217fe6875525511f4447bd3291fa09da31 100644
--- a/src/knot/worker/pool.c
+++ b/src/knot/worker/pool.c
@@ -36,8 +36,7 @@ struct worker_pool {
 	pthread_mutex_t lock;
 	pthread_cond_t wake;
 
-	bool suspended;
-	bool terminating;
+	bool terminating;	/*!< Is the pool terminating? .*/
 	worker_queue_t tasks;
 };
 
@@ -63,11 +62,6 @@ static int worker_main(dthread_t *thread)
 			break;
 		}
 
-		if (pool->suspended) {
-			pthread_cond_wait(&pool->wake, &pool->lock);
-			continue;
-		}
-
 		task_t *task = worker_queue_dequeue(&pool->tasks);
 		if (task == NULL) {
 			pthread_cond_wait(&pool->wake, &pool->lock);
@@ -80,6 +74,8 @@ static int worker_main(dthread_t *thread)
 		pthread_mutex_unlock(&pool->lock);
 		task->run(task);
 		pthread_mutex_lock(&pool->lock);
+
+		pthread_cond_broadcast(&pool->wake);
 	}
 
 	pthread_mutex_unlock(&pool->lock);
@@ -166,26 +162,16 @@ void worker_pool_join(worker_pool_t *pool)
 	dt_join(pool->threads);
 }
 
-void worker_pool_suspend(worker_pool_t *pool)
+void worker_pool_wait(worker_pool_t *pool)
 {
 	if (!pool) {
 		return;
 	}
 
 	pthread_mutex_lock(&pool->lock);
-	pool->suspended = true;
-	pthread_mutex_unlock(&pool->lock);
-}
-
-void worker_pool_continue(worker_pool_t *pool)
-{
-	if (!pool) {
-		return;
+	while (!EMPTY_LIST(pool->tasks.list)) {
+		pthread_cond_wait(&pool->wake, &pool->lock);
 	}
-
-	pthread_mutex_lock(&pool->lock);
-	pool->suspended = false;
-	pthread_cond_broadcast(&pool->wake);
 	pthread_mutex_unlock(&pool->lock);
 }
 
@@ -197,9 +183,7 @@ void worker_pool_assign(worker_pool_t *pool, task_t *task)
 
 	pthread_mutex_lock(&pool->lock);
 	worker_queue_enqueue(&pool->tasks, task);
-	if (!pool->suspended) {
-		pthread_cond_signal(&pool->wake);
-	}
+	pthread_cond_signal(&pool->wake);
 	pthread_mutex_unlock(&pool->lock);
 }
 
diff --git a/src/knot/worker/pool.h b/src/knot/worker/pool.h
index 171140983220e8edb85ca54067395ad6bac302e1..9ffa04d41fb0ed3054609bffbec9ae10186a2702 100644
--- a/src/knot/worker/pool.h
+++ b/src/knot/worker/pool.h
@@ -51,14 +51,10 @@ void worker_pool_stop(worker_pool_t *pool);
 void worker_pool_join(worker_pool_t *pool);
 
 /*!
- * \brief Suspend execution of new tasks, existing task are not terminated.
- */
-void worker_pool_suspend(worker_pool_t *pool);
-
-/*!
- * \brief Continue execution of new tasks.
+ * \brief Wait till the number of pending tasks is zero.
+ *
  */
-void worker_pool_continue(worker_pool_t *pool);
+void worker_pool_wait(worker_pool_t *pool);
 
 /*!
  * \brief Assign a task to be performed by a worker in the pool.
diff --git a/src/knot/zone/events.c b/src/knot/zone/events.c
index 91b63f0079af0704c78a11a554c07c1e7b18d208..e3a7fdaa801dc2740a66c122b480b5e83793e0db 100644
--- a/src/knot/zone/events.c
+++ b/src/knot/zone/events.c
@@ -609,7 +609,7 @@ static const event_info_t EVENT_INFO[] = {
         { ZONE_EVENT_RELOAD,  event_reload,  "reload" },
         { ZONE_EVENT_REFRESH, event_refresh, "refresh" },
         { ZONE_EVENT_XFER,    event_xfer,    "transfer" },
-        { ZONE_EVENT_UPDATE,  event_update,  "UPDATE" },
+        { ZONE_EVENT_UPDATE,  event_update,  "update" },
         { ZONE_EVENT_EXPIRE,  event_expire,  "expiration" },
         { ZONE_EVENT_FLUSH,   event_flush,   "journal flush" },
         { ZONE_EVENT_NOTIFY,  event_notify,  "notify" },
@@ -734,7 +734,6 @@ void zone_events_deinit(zone_t *zone)
 	evsched_cancel(zone->events.event);
 	evsched_event_free(zone->events.event);
 
-	assert(zone->events.running == false);
 	pthread_mutex_destroy(&zone->events.mx);
 
 	memset(&zone->events, 0, sizeof(zone->events));
@@ -750,6 +749,12 @@ void zone_events_schedule_at(zone_t *zone, zone_event_type_t type, time_t time)
 
 	pthread_mutex_lock(&events->mx);
 
+	/* Don't schedule new events if frozen. */
+	if (events->frozen) {
+		pthread_mutex_unlock(&events->mx);
+		return;
+	}
+
 	time_t current = event_get_time(events, type);
 	if (current == 0 || time == 0 || time < current) {
 		event_set_time(events, type, time);
@@ -772,7 +777,7 @@ void zone_events_cancel(zone_t *zone, zone_event_type_t type)
 	zone_events_schedule_at(zone, type, 0);
 }
 
-void zone_events_cancel_all(zone_t *zone)
+void zone_events_freeze(zone_t *zone)
 {
 	if (!zone) {
 		return;
@@ -781,10 +786,9 @@ void zone_events_cancel_all(zone_t *zone)
 	zone_events_t *events = &zone->events;
 
 	pthread_mutex_lock(&events->mx);
-	for (int i = 0; i < ZONE_EVENT_COUNT; i++) {
-		event_set_time(events, i, 0);
-	}
-	reschedule(events);
+	/* Cancel pending event and prevent new. */
+	events->frozen = true;
+	evsched_cancel(events->event);
 	pthread_mutex_unlock(&events->mx);
 }
 
diff --git a/src/knot/zone/events.h b/src/knot/zone/events.h
index f1638863367266d057c5ee9bbcceb8bb8b0f05c3..ebd7e7b5179d9404d2ead17f025c27ec07ece923 100644
--- a/src/knot/zone/events.h
+++ b/src/knot/zone/events.h
@@ -48,6 +48,7 @@ typedef enum zone_event_type {
 typedef struct zone_events {
 	pthread_mutex_t mx;		//!< Mutex protecting the struct.
 	bool running;			//!< Some zone event is being run.
+	bool frozen;			//!< Terminated, don't schedule new events.
 
 	event_t *event;			//!< Scheduler event.
 	worker_pool_t *pool;		//!< Server worker pool.
@@ -96,9 +97,9 @@ void zone_events_schedule(struct zone_t *zone, zone_event_type_t type, unsigned
 void zone_events_cancel(struct zone_t *zone, zone_event_type_t type);
 
 /*!
- * \brief Cancel all zone events.
+ * \brief Freeze all zone events and prevent new events from running.
  */
-void zone_events_cancel_all(struct zone_t *zone);
+void zone_events_freeze(struct zone_t *zone);
 
 /*!
  * \brief Start the events processing.
diff --git a/src/knot/zone/zonedb-load.c b/src/knot/zone/zonedb-load.c
index cb89897047624b221835e7d28ca1ca347e538934..31d3ea03e23dcc43907578084dceef10624c9090 100644
--- a/src/knot/zone/zonedb-load.c
+++ b/src/knot/zone/zonedb-load.c
@@ -166,7 +166,7 @@ static zone_t *create_zone(conf_zone_t *conf, server_t *server, zone_t *old_zone
  * new. New zones are loaded.
  *
  * \param conf    New server configuration.
- * \param old_db  Old zone database (can be NULL).
+ * \param server  Server instance.
  *
  * \return New zone database.
  */
@@ -206,9 +206,9 @@ static knot_zonedb_t *create_zonedb(const conf_t *conf, server_t *server)
 }
 
 /*!
- * \brief Remove old zones and zone database.
+ * \brief Schedule deletion of old zones, and free the zone db structure.
  *
- * \note Zone may be preserved in the new zone database, in this case
+ * \note Zone content may be preserved in the new zone database, in this case
  *       new and old zone share the contents. Shared content is not freed.
  *
  * \param db_new New zone database.
@@ -234,7 +234,6 @@ static int remove_old_zonedb(const knot_zonedb_t *db_new, knot_zonedb_t *db_old)
 		knot_zonedb_iter_next(&it);
 	}
 
-	/* Delete all deprecated zones and delete the old database. */
 	knot_zonedb_deep_free(&db_old);
 
 	return KNOT_EOK;
@@ -252,12 +251,6 @@ int zonedb_reload(const conf_t *conf, struct server_t *server)
 		return KNOT_EINVAL;
 	}
 
-	/* Freeze zone timers. */
-#warning "Workers have to be suspended and unsuspended outside this function."
-	if (server->zone_db) {
-		//knot_zonedb_foreach(server->zone_db, zone_events_freeze);
-	}
-
 	/* Insert all required zones to the new zone DB. */
 	/*! \warning RCU must not be locked as some contents switching will
 	             be required. */
@@ -277,11 +270,6 @@ int zonedb_reload(const conf_t *conf, struct server_t *server)
 	/* Wait for readers to finish reading old zone database. */
 	synchronize_rcu();
 
-	/* Thaw zone events now that the database is published. */
-	if (server->zone_db) {
-		knot_zonedb_foreach(server->zone_db, zone_events_start);
-	}
-
 	/*
 	 * Remove all zones present in the new DB from the old DB.
 	 * No new thread can access these zones in the old DB, as the
diff --git a/src/utils/dig/dig_exec.c b/src/utils/dig/dig_exec.c
index 84304b84154ef8983118126ccb08283e01be579a..6ccac6651c901ad114187ec2052107afa2282035 100644
--- a/src/utils/dig/dig_exec.c
+++ b/src/utils/dig/dig_exec.c
@@ -653,7 +653,7 @@ static void process_query(const query_t *query)
 				return;
 			// SERVFAIL.
 			} else if (ret == 1 && query->servfail_stop == true) {
-				WARN("failed to query server %s#%s(%s)\n",
+				WARN("failed to query server %s@%s(%s)\n",
 				     remote->name, remote->service,
 				     get_sockname(socktype));
 				net_clean(&net);
@@ -663,7 +663,7 @@ static void process_query(const query_t *query)
 
 			if (i < query->retries) {
 				printf("\n");
-				DBG("retrying server %s#%s(%s)\n",
+				DBG("retrying server %s@%s(%s)\n",
 				    remote->name, remote->service,
 				    get_sockname(socktype));
 			}
@@ -671,7 +671,7 @@ static void process_query(const query_t *query)
 			net_clean(&net);
 		}
 
-		WARN("failed to query server %s#%s(%s)\n",
+		WARN("failed to query server %s@%s(%s)\n",
 		     remote->name, remote->service, get_sockname(socktype));
 
 		// If not last server, print separation.
@@ -905,7 +905,7 @@ static void process_xfr(const query_t *query)
 	}
 
 	if (ret != 0) {
-		ERR("failed to query server %s#%s(%s)\n",
+		ERR("failed to query server %s@%s(%s)\n",
 		    remote->name, remote->service, get_sockname(socktype));
 	}