diff --git a/src/common/evsched.c b/src/common/evsched.c
index 5061fe670047370cb22bc4ccc446f6bc982cc13c..6fa0fa8c6f178924893ad6a6a00daf17ccf5dc5f 100644
--- a/src/common/evsched.c
+++ b/src/common/evsched.c
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#include "common/errcode.h"
 #include "common/evsched.h"
 
 /*! \todo Fix properly (issue #1581). */
@@ -64,13 +65,13 @@ static void evsched_settimer(event_t *e, uint32_t dt)
 }
 
 /*! \brief Singleton application-wide event scheduler. */
-evsched_t *s_evsched = 0;
+evsched_t *s_evsched = NULL;
 
 evsched_t *evsched_new()
 {
 	evsched_t *s = malloc(sizeof(evsched_t));
 	if (!s) {
-		return 0;
+		return NULL;
 	}
 	memset(s, 0, sizeof(evsched_t));
 
@@ -88,10 +89,7 @@ evsched_t *evsched_new()
 
 void evsched_delete(evsched_t **s)
 {
-	if (!s) {
-		return;
-	}
-	if (!*s) {
+	if (s == NULL || *s == NULL) {
 		return;
 	}
 
@@ -119,13 +117,13 @@ void evsched_delete(evsched_t **s)
 
 	/* Free scheduler. */
 	free(*s);
-	*s = 0;
+	*s = NULL;
 }
 
 event_t *evsched_event_new(evsched_t *s, int type)
 {
 	if (!s) {
-		return 0;
+		return NULL;
 	}
 
 	/* Allocate. */
@@ -165,7 +163,7 @@ event_t* evsched_next(evsched_t *s)
 {
 	/* Check. */
 	if (!s) {
-		return 0;
+		return NULL;
 	}
 
 	/* Lock calendar. */
@@ -214,31 +212,31 @@ event_t* evsched_next(evsched_t *s)
 
 	/* Unlock calendar, this shouldn't happen. */
 	pthread_mutex_unlock(&s->mx);
-	return 0;
+	return NULL;
 
 }
 
 int evsched_event_finished(evsched_t *s)
 {
 	if (!s) {
-		return -1;
+		return KNOT_EINVAL;
 	}
 
 	/* Mark as finished. */
 	if (s->cur) {
 		s->cur = NULL;
 		pthread_mutex_unlock(&s->rl);
-		return 0;
+		return KNOT_EOK;
 	}
 
-	/* Finished event is not current. */
-	return -1;
+	/* No event running. */
+	return KNOT_ENOTRUNNING;
 }
 
 int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt)
 {
 	if (!s || !ev) {
-		return -1;
+		return KNOT_EINVAL;
 	}
 
 	/* Update event timer. */
@@ -254,19 +252,19 @@ int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt)
 	pthread_cond_broadcast(&s->notify);
 	pthread_mutex_unlock(&s->mx);
 
-	return 0;
+	return KNOT_EOK;
 }
 
 event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, uint32_t dt)
 {
 	if (!s) {
-		return 0;
+		return NULL;
 	}
 
 	/* Create event. */
 	event_t *e = evsched_event_new(s, EVSCHED_CB);
 	if (!e) {
-		return 0;
+		return NULL;
 	}
 	e->cb = cb;
 	e->data = data;
@@ -274,7 +272,7 @@ event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, uint32_t d
 	/* Schedule. */
 	if (evsched_schedule(s, e, dt) != 0) {
 		evsched_event_free(s, e);
-		e = 0;
+		e = NULL;
 	}
 
 	return e;
@@ -283,30 +281,30 @@ event_t* evsched_schedule_cb(evsched_t *s, event_cb_t cb, void *data, uint32_t d
 event_t* evsched_schedule_term(evsched_t *s, uint32_t dt)
 {
 	if (!s) {
-		return 0;
+		return NULL;
 	}
 
 	/* Create event. */
 	event_t *e = evsched_event_new(s, EVSCHED_TERM);
 	if (!e) {
-		return 0;
+		return NULL;
 	}
 
 	/* Schedule. */
 	if (evsched_schedule(s, e, dt) != 0) {
 		evsched_event_free(s, e);
-		e = 0;
+		e = NULL;
 	}
 
 	return e;
 }
 
-int evsched_cancel(evsched_t *s, event_t *ev)
+static int evsched_try_cancel(evsched_t *s, event_t *ev)
 {
-	int found;
+	int found = 0;
 
 	if (!s || !ev) {
-		return -1;
+		return KNOT_EINVAL;
 	}
 
 	/* Make sure not running. */
@@ -325,7 +323,7 @@ int evsched_cancel(evsched_t *s, event_t *ev)
 	 */
 	if (s->cur == ev) {
 		s->cur = NULL; /* Invalidate */
-        found = 1; /* Mark as found (although not in heap). */
+		found = KNOT_EAGAIN; /* Already ran, try again. */
 	}
 
 	/* Unlock calendar. */
@@ -334,6 +332,25 @@ int evsched_cancel(evsched_t *s, event_t *ev)
 
 	/* Enable running events. */
 	pthread_mutex_unlock(&s->rl);
+	if (found) {
+		return KNOT_EOK;
+	}
+
+	return KNOT_ENOENT;
+}
+
+int evsched_cancel(evsched_t *s, event_t *ev)
+{
+	if (!s || !ev) {
+		return KNOT_EINVAL;
+	}
+
+	/* Event may have already run, try again. */
+	int ret = KNOT_EAGAIN;
+	while (ret == KNOT_EAGAIN) {
+		ret = evsched_try_cancel(s, ev);
+	}
 
-	return found;
+	/* Now we're sure event is cancelled or finished. */
+	return KNOT_EOK;
 }
diff --git a/src/common/evsched.h b/src/common/evsched.h
index 907874985310685f422bbb0476622f82ea54729f..4e710a59b803cf1e1e1dd4224bebe4775a7aecbe 100644
--- a/src/common/evsched.h
+++ b/src/common/evsched.h
@@ -155,8 +155,9 @@ event_t* evsched_next(evsched_t *s);
  *
  * \param s Event scheduler.
  *
- * \retval 0 if successful.
- * \retval -1 on errors.
+ * \retval KNOT_EOK if successful.
+ * \retval KNOT_EINVAL
+ * \retval KNOT_ENOTRUNNING
  */
 int evsched_event_finished(evsched_t *s);
 
@@ -167,8 +168,8 @@ int evsched_event_finished(evsched_t *s);
  * \param ev Prepared event.
  * \param dt Time difference in milliseconds from now (dt is relative).
  *
- * \retval 0 on success.
- * \retval <0 on error.
+ * \retval KNOT_EOK on success.
+ * \retval KNOT_EINVAL
  */
 int evsched_schedule(evsched_t *s, event_t *ev, uint32_t dt);
 
@@ -212,9 +213,8 @@ event_t* evsched_schedule_term(evsched_t *s, uint32_t dt);
  * \param s Event scheduler.
  * \param ev Scheduled event.
  *
- * \retval 0 if already ran.
- * \retval 1 if found and cancelled.
- * \retval <0 on error.
+ * \retval KNOT_EOK
+ * \retval KNOT_EINVAL
  */
 int evsched_cancel(evsched_t *s, event_t *ev);
 
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index 173f260e09498eafc9ec1bebaa65bcaaae9eb88f..9e8840968d908583daf01cabd971fdc45a6cc528 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -508,6 +508,9 @@ int zones_changesets_from_binary(knot_changesets_t *chgsets)
 	knot_changeset_t* chs = NULL;
 	WALK_LIST(chs, chgsets->sets) {
 		/* Read changeset flags. */
+		if (chs->data == NULL) {
+			return KNOT_EMALF;
+		}
 		size_t remaining = chs->size;
 		memcpy(&chs->flags, chs->data, sizeof(uint32_t));
 		remaining -= sizeof(uint32_t);
@@ -2607,8 +2610,6 @@ done:
 	knot_changesets_free(&chs);
 	free(msgpref);
 
-	evsched_event_free(event->parent, event);
-	zd->dnssec_timer = NULL;
 	if (expires_at != 0) {
 		ret = zones_schedule_dnssec(zone,
 		                            expiration_to_relative(expires_at,
@@ -2651,8 +2652,6 @@ int zones_cancel_dnssec(knot_zone_t *zone)
 
 	if (zd->dnssec_timer) {
 		evsched_cancel(scheduler, zd->dnssec_timer);
-		evsched_event_free(scheduler, zd->dnssec_timer);
-		zd->dnssec_timer = NULL;
 	}
 
 	return KNOT_EOK;
@@ -2673,16 +2672,20 @@ int zones_schedule_dnssec(knot_zone_t *zone, uint32_t time, bool force)
 	              time / 3600000);
 	free(zname);
 
-//	TODO: throw an error if the new signing event is more in the future than the old one
-
-	if (force) {
-		zd->dnssec_timer = evsched_schedule_cb(scheduler,
-		                                       zones_dnssec_forced_ev,
-		                                       zone, time);
+	if (zd->dnssec_timer) {
+		// Event created already, just reschedule
+		evsched_schedule(scheduler, zd->dnssec_timer, time);
 	} else {
-		zd->dnssec_timer = evsched_schedule_cb(scheduler,
-		                                       zones_dnssec_regular_ev,
-		                                       zone, time);
+		// Create new event
+		if (force) {
+			zd->dnssec_timer = evsched_schedule_cb(scheduler,
+			                                       zones_dnssec_forced_ev,
+			                                       zone, time);
+		} else {
+			zd->dnssec_timer = evsched_schedule_cb(scheduler,
+			                                       zones_dnssec_regular_ev,
+			                                       zone, time);
+		}
 	}
 
 	return KNOT_EOK;
@@ -2950,6 +2953,8 @@ int zones_journal_apply(knot_zone_t *zone)
 int zones_do_diff_and_sign(const conf_zone_t *z, knot_zone_t *zone,
                            const knot_nameserver_t *ns, bool zone_changed)
 {
+	/* Cancel possibly running signing event. */
+	zones_cancel_dnssec(zone);
 	/* Calculate differences. */
 	rcu_read_lock();
 	knot_zone_t *z_old = knot_zonedb_find_zone(ns->zone_db,
@@ -3001,6 +3006,7 @@ int zones_do_diff_and_sign(const conf_zone_t *z, knot_zone_t *zone,
 	knot_changesets_t *sec_chs = NULL;
 	knot_changeset_t *sec_ch = NULL;
 	knot_zone_contents_t *new_contents = NULL;
+	uint32_t expires_at = 0;
 	if (z->dnssec_enable) {
 		sec_chs = knot_changesets_create();
 		if (sec_chs == NULL) {
@@ -3026,7 +3032,6 @@ int zones_do_diff_and_sign(const conf_zone_t *z, knot_zone_t *zone,
 		log_zone_info("DNSSEC: Zone %s - Signing started...\n",
 		              z->name);
 
-		uint32_t expires_at = 0;
 		int ret = knot_dnssec_zone_sign(zone, sec_ch, soa_up,
 		                                &expires_at);
 		if (ret != KNOT_EOK) {
@@ -3035,21 +3040,6 @@ int zones_do_diff_and_sign(const conf_zone_t *z, knot_zone_t *zone,
 			rcu_read_unlock();
 			return ret;
 		}
-
-		// Schedule next zone signing
-		zones_cancel_dnssec(zone);
-		ret = zones_schedule_dnssec(zone,
-		                            expiration_to_relative(expires_at,
-		                                                   zone),
-		                            false);
-		if (ret != KNOT_EOK) {
-			knot_changesets_free(&diff_chs);
-			knot_changesets_free(&sec_chs);
-			rcu_read_unlock();
-			return ret;
-		}
-	} else {
-		zones_cancel_dnssec(zone);
 	}
 
 	/* Merge changesets created by diff and sign. */
@@ -3116,5 +3106,14 @@ int zones_do_diff_and_sign(const conf_zone_t *z, knot_zone_t *zone,
 	rcu_read_unlock();
 
 	zones_free_merged_changesets(diff_chs, sec_chs);
+
+	// Schedule next zone signing
+	if (z->dnssec_enable) {
+		ret = zones_schedule_dnssec(zone,
+					    expiration_to_relative(expires_at,
+								   zone),
+					    false);
+	}
+
 	return ret;
 }
diff --git a/tests/events.c b/tests/events.c
index 664409d30253f6cbbe141987d2751cfcd6fc4415..2ba8177c19ebaccd36f44c8dd347c586a5e9d105 100644
--- a/tests/events.c
+++ b/tests/events.c
@@ -22,6 +22,7 @@
 
 #include "common/evqueue.h"
 #include "common/evsched.h"
+#include "common/errcode.h"
 
 void* term_thr(void *arg)
 {
@@ -146,7 +147,7 @@ int main(int argc, char *argv[])
 	// 7. Insert and immediately cancel an event
 	e = evsched_schedule_cb(s, 0, (void*)0xdead, 1000);
 	ret = evsched_cancel(s, e);
-	ok(ret >= 0, "evsched: inserted and cancelled an event");
+	ok(ret == KNOT_EOK, "evsched: inserted and cancelled an event");
 	if (e) {
 		evsched_event_free(s, e);
 	}