diff --git a/Knot.files b/Knot.files
index d865ad67868e3d59bbd8242278302d2ec5edc20f..e766ce60fae3a81d9f3c0b57797ebfc221a89335 100644
--- a/Knot.files
+++ b/Knot.files
@@ -128,14 +128,13 @@ src/knot/events/events.c
 src/knot/events/events.h
 src/knot/events/handlers.h
 src/knot/events/handlers/dnssec.c
-src/knot/events/handlers/ds_check.c
-src/knot/events/handlers/ds_push.c
 src/knot/events/handlers/expire.c
 src/knot/events/handlers/flush.c
 src/knot/events/handlers/freeze_thaw.c
 src/knot/events/handlers/load.c
 src/knot/events/handlers/notify.c
 src/knot/events/handlers/nsec3resalt.c
+src/knot/events/handlers/parent_ds_query.c
 src/knot/events/handlers/refresh.c
 src/knot/events/handlers/update.c
 src/knot/events/replan.c
diff --git a/doc/man/knot.conf.5in b/doc/man/knot.conf.5in
index e4f79f69463b36f2ad48b5bd58385ce6d3cb1e0a..abaed61297094b48a9d4abb1502ae6395da20f22 100644
--- a/doc/man/knot.conf.5in
+++ b/doc/man/knot.conf.5in
@@ -706,7 +706,6 @@ policy:
     nsec3\-salt\-lifetime: TIME
     signing\-threads: INT
     ksk\-submission: submission_id
-    ds\-push: remote_id
     cds\-cdnskey\-publish: none | delete\-dnssec | rollover | always | double\-ds
     offline\-ksk: BOOL
 .ft P
@@ -930,28 +929,6 @@ A reference to \fI\%submission\fP section holding parameters of
 KSK submittion checks.
 .sp
 \fIDefault:\fP not set
-.SS ds\-push
-.sp
-A \fI\%reference\fP to parent\(aqs DNS server. Whenever the CDS record in
-this zone is changed, corresponding DS record is sent as an update (DDNS) to
-parent DNS server.
-.sp
-\fBNOTE:\fP
-.INDENT 0.0
-.INDENT 3.5
-For proper operation ref:\fIcds\-cdnskey\-publish<policy_cds\-cdnskey\-publish>\fP
-must not be disabled.
-.UNINDENT
-.UNINDENT
-.sp
-\fBNOTE:\fP
-.INDENT 0.0
-.INDENT 3.5
-This feature does not work with Onlinesign module.
-.UNINDENT
-.UNINDENT
-.sp
-\fIDefault:\fP not set
 .SS signing\-threads
 .sp
 When signing zone or update, use this number of threads for parallel signing.
diff --git a/doc/reference.rst b/doc/reference.rst
index d45222642e76bd3cfae42305557c50fd13f394fc..64e22889b20d76f7d0a6f706d079c447e63c6fa3 100644
--- a/doc/reference.rst
+++ b/doc/reference.rst
@@ -770,7 +770,6 @@ DNSSEC policy configuration.
      nsec3-salt-lifetime: TIME
      signing-threads: INT
      ksk-submission: submission_id
-     ds-push: remote_id
      cds-cdnskey-publish: none | delete-dnssec | rollover | always | double-ds
      offline-ksk: BOOL
 
@@ -1035,24 +1034,6 @@ KSK submittion checks.
 
 *Default:* not set
 
-.. _policy_ds-push:
-
-ds-push
--------
-
-A :ref:`reference<remote_id>` to parent's DNS server. Whenever the CDS record in
-this zone is changed, corresponding DS record is sent as an update (DDNS) to
-parent DNS server.
-
-.. NOTE::
-   For proper operation ref:`cds-cdnskey-publish<policy_cds-cdnskey-publish>`
-   must not be disabled.
-
-.. NOTE::
-   This feature does not work with :ref:`Onlinesign<mod-onlinesign>` module.
-
-*Default:* not set
-
 .. _policy_signing-threads:
 
 signing-threads
diff --git a/scripts/timerdb-info.py b/scripts/timerdb-info.py
index 6a7cd3610989c510f369fb4bca57618e9854f606..26eb079c8511d95a22b4169b4aee50ff3c3ad8b9 100755
--- a/scripts/timerdb-info.py
+++ b/scripts/timerdb-info.py
@@ -37,10 +37,8 @@ class TimerDBInfo:
                 0x82: ("last_refresh", cls.format_timestamp),
                 0x83: ("next_refresh", cls.format_timestamp),
                 # knot >= 2.6
-                0x84: ("last_resalt",   cls.format_timestamp),
-                0x85: ("next_ds_check", cls.format_timestamp),
-                # knot >= 2.8
-                0x86: ("next_ds_push",  cls.format_timestamp),
+                0x84: ("last_resalt",      cls.format_timestamp),
+                0x85: ("next_parent_ds_q", cls.format_timestamp),
         }
         if id in timers:
             return (timers[id][0], timers[id][1](value))
diff --git a/src/knot/Makefile.inc b/src/knot/Makefile.inc
index ea2cbb497f5277990428853626cc5f90b5230d81..f9a5f4d2dbc643fc025a35242bb7bc45a3fb8c74 100644
--- a/src/knot/Makefile.inc
+++ b/src/knot/Makefile.inc
@@ -66,8 +66,6 @@ libknotd_la_SOURCES = \
 	knot/events/events.h			\
 	knot/events/handlers.h			\
 	knot/events/handlers/dnssec.c		\
-	knot/events/handlers/ds_check.c		\
-	knot/events/handlers/ds_push.c		\
 	knot/events/handlers/expire.c		\
 	knot/events/handlers/flush.c		\
 	knot/events/handlers/freeze_thaw.c	\
@@ -76,6 +74,7 @@ libknotd_la_SOURCES = \
 	knot/events/handlers/nsec3resalt.c	\
 	knot/events/handlers/refresh.c		\
 	knot/events/handlers/update.c		\
+	knot/events/handlers/parent_ds_query.c	\
 	knot/events/replan.c			\
 	knot/events/replan.h			\
 	knot/nameserver/axfr.c			\
diff --git a/src/knot/conf/schema.c b/src/knot/conf/schema.c
index 97ba8c586400621a033fa740b5ab954a65e63ace..cc081ebf52c67ea4e0145e6a176908c76d39f5cd 100644
--- a/src/knot/conf/schema.c
+++ b/src/knot/conf/schema.c
@@ -291,8 +291,6 @@ static const yp_item_t desc_policy[] = {
 	                                   CONF_IO_FRLD_ZONES },
 	{ C_KSK_SBM,             YP_TREF,  YP_VREF = { C_SBM }, CONF_IO_FRLD_ZONES,
 	                                   { check_ref } },
-	{ C_DS_PUSH,             YP_TREF,  YP_VREF = { C_RMT }, YP_FMULTI | CONF_IO_FRLD_ZONES,
-	                                   { check_ref } },
 	{ C_SIGNING_THREADS,     YP_TINT,  YP_VINT = { 1, UINT16_MAX, 1 } },
 	{ C_CDS_CDNSKEY,         YP_TOPT,  YP_VOPT = { cds_cdnskey, CDS_CDNSKEY_ROLLOVER } },
 	{ C_OFFLINE_KSK,         YP_TBOOL, YP_VNONE, CONF_IO_FRLD_ZONES },
diff --git a/src/knot/conf/schema.h b/src/knot/conf/schema.h
index 742072b25e5137603a3d769e794e7bc4a7e5a8fb..befbf2bd9ef5b274ea151de11bb2450111f6c4c0 100644
--- a/src/knot/conf/schema.h
+++ b/src/knot/conf/schema.h
@@ -41,7 +41,6 @@
 #define C_DNSSEC_POLICY		"\x0D""dnssec-policy"
 #define C_DNSSEC_SIGNING	"\x0E""dnssec-signing"
 #define C_DOMAIN		"\x06""domain"
-#define C_DS_PUSH		"\x07""ds-push"
 #define C_ECS			"\x12""edns-client-subnet"
 #define C_FILE			"\x04""file"
 #define C_GLOBAL_MODULE		"\x0D""global-module"
diff --git a/src/knot/conf/tools.c b/src/knot/conf/tools.c
index 88c58483c3b9d0de70d2b9bd579f72cd40b4d701..1e3d3c4a4322fa913b088857e0d5c7496fd9ed35 100644
--- a/src/knot/conf/tools.c
+++ b/src/knot/conf/tools.c
@@ -400,16 +400,6 @@ int check_policy(
 		}
 	}
 
-	conf_val_t cds_cdnskey = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
-	                                            C_CDS_CDNSKEY, args->id, args->id_len);
-	conf_val_t ds_push = conf_rawid_get_txn(args->extra->conf, args->extra->txn, C_POLICY,
-	                                        C_DS_PUSH, args->id, args->id_len);
-
-	if (conf_val_count(&ds_push) > 0 && conf_opt(&cds_cdnskey) == CDS_CDNSKEY_NONE) {
-		args->err_str = "DS push requires enabled CDS/CDNSKEY publication";
-		return KNOT_EINVAL;
-	}
-
 	return KNOT_EOK;
 }
 
diff --git a/src/knot/dnssec/key-events.c b/src/knot/dnssec/key-events.c
index 3172efbb93dee63ed015b5402294ea4c3d0de8c3..658fa770331ba286cee2e5744aaef94d5577f2bd 100644
--- a/src/knot/dnssec/key-events.c
+++ b/src/knot/dnssec/key-events.c
@@ -594,7 +594,7 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_roll_flags_t flags,
 				ret = generate_key(ctx, GEN_KSK_FLAGS, ctx->now, false);
 			}
 			if (ret == KNOT_EOK) {
-				reschedule->plan_ds_check = true;
+				reschedule->plan_ds_query = true;
 				plan_ds_keytag = dnssec_key_get_keytag(ctx->zone->keys[0].key);
 			}
 		}
@@ -685,7 +685,7 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_roll_flags_t flags,
 		case SUBMIT:
 			ret = submit_key(ctx, next.key);
 			if (ret == KNOT_EOK) {
-				reschedule->plan_ds_check = true;
+				reschedule->plan_ds_query = true;
 				plan_ds_keytag = dnssec_key_get_keytag(next.key->key);
 			}
 			break;
@@ -716,7 +716,7 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_roll_flags_t flags,
 
 	if (ret == KNOT_EOK && next.ready_key >= 0) {
 		// just to make sure DS check is scheduled
-		reschedule->plan_ds_check = true;
+		reschedule->plan_ds_query = true;
 		plan_ds_keytag = next.ready_key;
 	}
 
@@ -728,7 +728,7 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_sign_roll_flags_t flags,
 		ret = kdnssec_ctx_commit(ctx);
 	}
 
-	if (ret == KNOT_EOK && reschedule->plan_ds_check) {
+	if (ret == KNOT_EOK && reschedule->plan_ds_query) {
 		char param[32];
 		(void)snprintf(param, sizeof(param), "KEY_SUBMISSION=%hu", plan_ds_keytag);
 		log_fmt_zone(LOG_NOTICE, LOG_SOURCE_ZONE, ctx->zone->dname, param,
diff --git a/src/knot/dnssec/zone-events.h b/src/knot/dnssec/zone-events.h
index 292bdb1adf39cbb8c9063cc7e01a111fb6c60442..7039d7b29d016309616bf5e24cfbdc8390046e83 100644
--- a/src/knot/dnssec/zone-events.h
+++ b/src/knot/dnssec/zone-events.h
@@ -48,7 +48,7 @@ typedef struct {
 	knot_time_t next_nsec3resalt;
 	knot_time_t last_nsec3resalt;
 	bool keys_changed;
-	bool plan_ds_check;
+	bool plan_ds_query;
 } zone_sign_reschedule_t;
 
 /*!
diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c
index 85a8ff0bcfe2ef1d400bd9dd316619bd8210d947..aa0f4140c27a89e4d91ffc1dfdcf5f9e38860c60 100644
--- a/src/knot/dnssec/zone-sign.c
+++ b/src/knot/dnssec/zone-sign.c
@@ -816,11 +816,6 @@ int knot_zone_sign_update_dnskeys(zone_update_t *update,
 
 	if (!knot_rrset_empty(&add_r.cds)) {
 		ret = changeset_add_addition(&ch, &add_r.cds, CHANGESET_CHECK);
-		if (node_rrtype_exists(ch.add->apex, KNOT_RRTYPE_CDS)) {
-			// there is indeed a change to CDS
-			update->zone->timers.next_ds_push = time(NULL);
-			zone_events_schedule_now(update->zone, ZONE_EVENT_DS_PUSH);
-		}
 		CHECK_RET;
 	}
 
diff --git a/src/knot/events/events.c b/src/knot/events/events.c
index 6082c042af93ebc7d0f3ec6e6bdf03b58b9fbf3c..f62843a6421dbd7c8be328f619cc6fb813e28f79 100644
--- a/src/knot/events/events.c
+++ b/src/knot/events/events.c
@@ -48,8 +48,7 @@ static const event_info_t EVENT_INFO[] = {
 	{ ZONE_EVENT_UFREEZE,      event_ufreeze,     "update freeze" },
 	{ ZONE_EVENT_UTHAW,        event_uthaw,       "update thaw" },
 	{ ZONE_EVENT_NSEC3RESALT,  event_nsec3resalt, "NSEC3 resalt" },
-	{ ZONE_EVENT_DS_CHECK,     event_ds_check,    "DS check" },
-	{ ZONE_EVENT_DS_PUSH,      event_ds_push,     "DS push" },
+	{ ZONE_EVENT_PARENT_DS_Q,  event_parent_ds_q, "parent DS query" },
 	{ 0 }
 };
 
@@ -80,7 +79,7 @@ bool ufreeze_applies(zone_event_type_t type)
 	case ZONE_EVENT_FLUSH:
 	case ZONE_EVENT_DNSSEC:
 	case ZONE_EVENT_NSEC3RESALT:
-	case ZONE_EVENT_DS_CHECK:
+	case ZONE_EVENT_PARENT_DS_Q:
 		return true;
 	default:
 		return false;
diff --git a/src/knot/events/events.h b/src/knot/events/events.h
index 53612f731ff9b38dc7584d99ef02529ffd1a5b82..e14daae0adf186423b14b26648788fd4a036ebfc 100644
--- a/src/knot/events/events.h
+++ b/src/knot/events/events.h
@@ -40,8 +40,7 @@ typedef enum zone_event_type {
 	ZONE_EVENT_UFREEZE,
 	ZONE_EVENT_UTHAW,
 	ZONE_EVENT_NSEC3RESALT,
-	ZONE_EVENT_DS_CHECK,
-	ZONE_EVENT_DS_PUSH,
+	ZONE_EVENT_PARENT_DS_Q,
 	// terminator
 	ZONE_EVENT_COUNT,
 } zone_event_type_t;
diff --git a/src/knot/events/handlers.h b/src/knot/events/handlers.h
index b000ba22f61684ab184cded5a6b9c4d1bad4ee5d..ca50ccbcac9d08054651e4e2256a05de054e558a 100644
--- a/src/knot/events/handlers.h
+++ b/src/knot/events/handlers.h
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -44,6 +44,4 @@ int event_uthaw(conf_t *conf, zone_t *zone);
 /*! \brief Recreates salt for NSEC3 hashing. */
 int event_nsec3resalt(conf_t *conf, zone_t *zone);
 /*! \brief When CDS/CDNSKEY published, look for matching DS */
-int event_ds_check(conf_t *conf, zone_t *zone);
-/*! \brief After change of CDS/CDNSKEY, push the new DS to parent zone as DDNS. */
-int event_ds_push(conf_t *conf, zone_t *zone);
+int event_parent_ds_q(conf_t *conf, zone_t *zone);
diff --git a/src/knot/events/handlers/dnssec.c b/src/knot/events/handlers/dnssec.c
index 50af00a6e2dc9a9270fc0c15900342882bcc7767..32d3b7d3d204059289e6fb19ad4bd3fffa3a5001 100644
--- a/src/knot/events/handlers/dnssec.c
+++ b/src/knot/events/handlers/dnssec.c
@@ -50,8 +50,8 @@ void event_dnssec_reschedule(conf_t *conf, zone_t *zone,
 
 	log_dnssec_next(zone->name, (time_t)refresh_at);
 
-	if (refresh->plan_ds_check) {
-		zone->timers.next_ds_check = now;
+	if (refresh->plan_ds_query) {
+		zone->timers.next_parent_ds_q = now;
 	}
 
 	if (refresh->last_nsec3resalt) {
@@ -60,7 +60,7 @@ void event_dnssec_reschedule(conf_t *conf, zone_t *zone,
 
 	zone_events_schedule_at(zone,
 		ZONE_EVENT_DNSSEC, refresh_at ? (time_t)refresh_at : ignore,
-		ZONE_EVENT_DS_CHECK, refresh->plan_ds_check ? now : ignore,
+		ZONE_EVENT_PARENT_DS_Q, refresh->plan_ds_query ? now : ignore,
 		ZONE_EVENT_NSEC3RESALT, refresh->next_nsec3resalt ? refresh->next_nsec3resalt : ignore,
 		ZONE_EVENT_NOTIFY, zone_changed ? now : ignore
 	);
diff --git a/src/knot/events/handlers/ds_push.c b/src/knot/events/handlers/ds_push.c
deleted file mode 100644
index 603dd8abb36fde46413afa4a579fd22bd5377378..0000000000000000000000000000000000000000
--- a/src/knot/events/handlers/ds_push.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include <assert.h>
-
-#include "knot/common/log.h"
-#include "knot/conf/conf.h"
-#include "knot/query/query.h"
-#include "knot/query/requestor.h"
-#include "knot/zone/zone.h"
-#include "libknot/errcode.h"
-
-struct ds_push_data {
-	const knot_dname_t *zone;
-	knot_dname_t *parent_soa;
-	knot_rrset_t del_old_ds;
-	knot_rrset_t new_ds;
-	const struct sockaddr *remote;
-	struct query_edns_data edns;
-};
-
-#define DS_PUSH_RETRY	600
-
-#define DS_PUSH_LOG(priority, zone, remote, fmt, ...) \
-	ns_log(priority, zone, LOG_OPERATION_DS_PUSH, LOG_DIRECTION_OUT, remote, \
-	       fmt, ## __VA_ARGS__)
-
-static const knot_rdata_t remove_cds = { 5, { 0, 0, 0, 0, 0 } };
-
-static int ds_push_begin(knot_layer_t *layer, void *params)
-{
-	layer->data = params;
-
-	return KNOT_STATE_PRODUCE;
-}
-
-static int parent_soa_produce(struct ds_push_data *data, knot_pkt_t *pkt)
-{
-	const knot_dname_t *query_name = knot_wire_next_label(data->zone, NULL);
-
-	int ret = knot_pkt_put_question(pkt, query_name, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
-	if (ret != KNOT_EOK) {
-		return KNOT_STATE_FAIL;
-	}
-
-	ret = query_put_edns(pkt, &data->edns);
-	if (ret != KNOT_EOK) {
-		return KNOT_STATE_FAIL;
-	}
-
-	return KNOT_STATE_CONSUME;
-}
-
-static int ds_push_produce(knot_layer_t *layer, knot_pkt_t *pkt)
-{
-	struct ds_push_data *data = layer->data;
-
-	query_init_pkt(pkt);
-
-	if (data->parent_soa == NULL) {
-		return parent_soa_produce(data, pkt);
-	}
-
-	knot_wire_set_opcode(pkt->wire, KNOT_OPCODE_UPDATE);
-	int ret = knot_pkt_put_question(pkt, data->parent_soa, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
-	if (ret != KNOT_EOK) {
-		return KNOT_STATE_FAIL;
-	}
-
-	knot_pkt_begin(pkt, KNOT_AUTHORITY);
-
-	assert(data->del_old_ds.type == KNOT_RRTYPE_DS);
-	ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, &data->del_old_ds, 0);
-	if (ret != KNOT_EOK) {
-		return KNOT_STATE_FAIL;
-	}
-
-	assert(data->new_ds.type == KNOT_RRTYPE_DS);
-	assert(!knot_rrset_empty(&data->new_ds));
-	if (knot_rdata_cmp(data->new_ds.rrs.rdata, &remove_cds) != 0) {
-		// Otherwise only remove DS - it was a special "remove CDS".
-		ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, &data->new_ds, 0);
-		if (ret != KNOT_EOK) {
-			return KNOT_STATE_FAIL;
-		}
-	}
-
-	query_put_edns(pkt, &data->edns);
-
-	return KNOT_STATE_CONSUME;
-}
-
-static const knot_rrset_t *sect_soa(const knot_pkt_t *pkt, knot_section_t sect)
-{
-	const knot_pktsection_t *s = knot_pkt_section(pkt, sect);
-	const knot_rrset_t *rr = s->count > 0 ? knot_pkt_rr(s, 0) : NULL;
-	if (rr == NULL || rr->type != KNOT_RRTYPE_SOA || rr->rrs.count != 1) {
-		return NULL;
-	}
-	return rr;
-}
-
-static int ds_push_consume(knot_layer_t *layer, knot_pkt_t *pkt)
-{
-	struct ds_push_data *data = layer->data;
-
-	if (data->parent_soa != NULL) {
-		// DS push has already been sent, just finish the action.
-		free(data->parent_soa);
-		return KNOT_STATE_DONE;
-	}
-
-	const knot_rrset_t *parent_soa = sect_soa(pkt, KNOT_ANSWER);
-	if (parent_soa == NULL) {
-		parent_soa = sect_soa(pkt, KNOT_AUTHORITY);
-	}
-	if (parent_soa == NULL) {
-		DS_PUSH_LOG(LOG_WARNING, data->zone, data->remote,
-		            "malformed message");
-		return KNOT_STATE_FAIL;
-	}
-
-	data->parent_soa = knot_dname_copy(parent_soa->owner, NULL);
-
-	return KNOT_STATE_RESET;
-}
-
-static int ds_push_reset(knot_layer_t *layer)
-{
-	(void)layer;
-	return KNOT_STATE_PRODUCE;
-}
-
-static const knot_layer_api_t DS_PUSH_API = {
-	.begin = ds_push_begin,
-	.produce = ds_push_produce,
-	.reset = ds_push_reset,
-	.consume = ds_push_consume,
-};
-
-static int send_ds_push(conf_t *conf, zone_t *zone,
-                        const conf_remote_t *parent, int timeout)
-{
-	knot_rrset_t zone_cds = node_rrset(zone->contents->apex, KNOT_RRTYPE_CDS);
-	if (knot_rrset_empty(&zone_cds)) {
-		return KNOT_EOK; // No CDS, do nothing.
-	}
-	zone_cds.type = KNOT_RRTYPE_DS;
-
-	struct ds_push_data data = {
-		.zone = zone->name,
-		.new_ds = zone_cds,
-		.remote = (struct sockaddr *)&parent->addr,
-	};
-
-	knot_rrset_init(&data.del_old_ds, zone->name, KNOT_RRTYPE_DS, KNOT_CLASS_ANY, 0);
-	query_edns_data_init(&data.edns, conf, zone->name, parent->addr.ss_family);
-
-	knot_requestor_t requestor;
-	knot_requestor_init(&requestor, &DS_PUSH_API, &data, NULL);
-
-	knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
-	if (pkt == NULL) {
-		knot_requestor_clear(&requestor);
-		return KNOT_ENOMEM;
-	}
-
-	const struct sockaddr *dst = (struct sockaddr *)&parent->addr;
-	const struct sockaddr *src = (struct sockaddr *)&parent->via;
-	knot_request_t *req = knot_request_make(NULL, dst, src, pkt, &parent->key, 0);
-	if (req == NULL) {
-		knot_request_free(req, NULL);
-		knot_requestor_clear(&requestor);
-		return KNOT_ENOMEM;
-	}
-
-	int ret = knot_requestor_exec(&requestor, req, timeout);
-
-	if (ret == KNOT_EOK && knot_pkt_ext_rcode(req->resp) == 0) {
-		DS_PUSH_LOG(LOG_INFO, zone->name, dst, "success");
-	} else if (knot_pkt_ext_rcode(req->resp) == 0) {
-		DS_PUSH_LOG(LOG_WARNING, zone->name, dst,
-		            "failed (%s)", knot_strerror(ret));
-	} else {
-		DS_PUSH_LOG(LOG_WARNING, zone->name, dst,
-		            "server responded with error '%s'",
-		            knot_pkt_ext_rcode_name(req->resp));
-	}
-
-	knot_request_free(req, NULL);
-	knot_requestor_clear(&requestor);
-
-	return ret;
-}
-
-int event_ds_push(conf_t *conf, zone_t *zone)
-{
-	assert(zone);
-
-	if (zone_contents_is_empty(zone->contents)) {
-		return KNOT_EOK;
-	}
-
-	int timeout = conf->cache.srv_tcp_reply_timeout * 1000;
-
-	conf_val_t policy_id = conf_zone_get(conf, C_DNSSEC_POLICY, zone->name);
-	conf_val_t ds_push = conf_id_get(conf, C_POLICY, C_DS_PUSH, &policy_id);
-	while (ds_push.code == KNOT_EOK) {
-		conf_val_t addr = conf_id_get(conf, C_RMT, C_ADDR, &ds_push);
-		size_t addr_count = conf_val_count(&addr);
-
-		int ret = KNOT_EOK;
-		for (int i = 0; i < addr_count; i++) {
-			conf_remote_t parent = conf_remote(conf, &ds_push, i);
-			ret = send_ds_push(conf, zone, &parent, timeout);
-			if (ret == KNOT_EOK) {
-				break;
-			}
-		}
-
-		if (ret != KNOT_EOK) {
-			time_t next_push = time(NULL) + DS_PUSH_RETRY;
-			zone_events_schedule_at(zone, ZONE_EVENT_DS_PUSH, next_push);
-			zone->timers.next_ds_push = next_push;
-		}
-
-		conf_val_next(&ds_push);
-	}
-
-	return KNOT_EOK;
-}
diff --git a/src/knot/events/handlers/ds_check.c b/src/knot/events/handlers/parent_ds_query.c
similarity index 88%
rename from src/knot/events/handlers/ds_check.c
rename to src/knot/events/handlers/parent_ds_query.c
index 96006f4d0f5f12772f35850c5f91383b42429109..2056a654a65bef55dee0afa9c68562b4c3204ec1 100644
--- a/src/knot/events/handlers/ds_check.c
+++ b/src/knot/events/handlers/parent_ds_query.c
@@ -17,7 +17,7 @@
 #include "knot/dnssec/ds_query.h"
 #include "knot/zone/zone.h"
 
-int event_ds_check(conf_t *conf, zone_t *zone)
+int event_parent_ds_q(conf_t *conf, zone_t *zone)
 {
 	kdnssec_ctx_t ctx = { 0 };
 
@@ -35,12 +35,12 @@ int event_ds_check(conf_t *conf, zone_t *zone)
 
 	ret = knot_parent_ds_query(&ctx, &keyset, conf->cache.srv_tcp_reply_timeout * 1000);
 
-	zone->timers.next_ds_check = 0;
+	zone->timers.next_parent_ds_q = 0;
 	if (ret != KNOT_EOK) {
 		if (ctx.policy->ksk_sbm_check_interval > 0) {
 			time_t next_check = time(NULL) + ctx.policy->ksk_sbm_check_interval;
-			zone->timers.next_ds_check = next_check;
-			zone_events_schedule_at(zone, ZONE_EVENT_DS_CHECK, next_check);
+			zone->timers.next_parent_ds_q = next_check;
+			zone_events_schedule_at(zone, ZONE_EVENT_PARENT_DS_Q, next_check);
 		}
 	} else {
 		zone_events_schedule_now(zone, ZONE_EVENT_DNSSEC);
diff --git a/src/knot/events/replan.c b/src/knot/events/replan.c
index 206bd3aad7398fade0d4b29fafcd60aa3b5821d4..9df2e2d10701c759b5c3fd781fd7c5a81919a5ea 100644
--- a/src/knot/events/replan.c
+++ b/src/knot/events/replan.c
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -130,14 +130,10 @@ void replan_from_timers(conf_t *conf, zone_t *zone)
 		}
 	}
 
-	time_t ds = zone->timers.next_ds_check;
+	time_t ds = zone->timers.next_parent_ds_q;
 	if (ds == 0) {
 		ds = TIME_IGNORE;
 	}
-	time_t ds_push = zone->timers.next_ds_push;
-	if (ds_push == 0) {
-		ds_push = TIME_IGNORE;
-	}
 
 	zone_events_schedule_at(zone,
 	                        ZONE_EVENT_REFRESH, refresh,
@@ -145,8 +141,7 @@ void replan_from_timers(conf_t *conf, zone_t *zone)
 	                        ZONE_EVENT_EXPIRE, expire,
 	                        ZONE_EVENT_FLUSH, flush,
 	                        ZONE_EVENT_NSEC3RESALT, resalt,
-	                        ZONE_EVENT_DS_CHECK, ds,
-				ZONE_EVENT_DS_PUSH, ds_push);
+	                        ZONE_EVENT_PARENT_DS_Q, ds);
 }
 
 void replan_load_new(zone_t *zone)
diff --git a/src/knot/modules/onlinesign/onlinesign.c b/src/knot/modules/onlinesign/onlinesign.c
index 6c55ece808732530e8d45941bb87a8528799313f..72538a66ea5b15a4b9473aa4bedae49264e817c8 100644
--- a/src/knot/modules/onlinesign/onlinesign.c
+++ b/src/knot/modules/onlinesign/onlinesign.c
@@ -518,7 +518,7 @@ static knotd_in_state_t pre_routine(knotd_in_state_t state, knot_pkt_t *pkt,
 		ret = knot_dnssec_key_rollover(mod->dnssec, KEY_ROLL_ALLOW_KSK_ROLL | KEY_ROLL_ALLOW_ZSK_ROLL, &resch);
 	}
 	if (ret == KNOT_EOK) {
-		if (resch.plan_ds_check && mod->dnssec->policy->ksk_sbm_check_interval > 0) {
+		if (resch.plan_ds_query && mod->dnssec->policy->ksk_sbm_check_interval > 0) {
 			ctx->event_parent_ds_q = mod->dnssec->now + mod->dnssec->policy->ksk_sbm_check_interval;
 		} else {
 			ctx->event_parent_ds_q = 0;
@@ -646,7 +646,7 @@ static int online_sign_ctx_new(online_sign_ctx_t **ctx_ptr, knotd_mod_t *mod)
 		return ret;
 	}
 
-	if (resch.plan_ds_check) {
+	if (resch.plan_ds_query) {
 		ctx->event_parent_ds_q = time(NULL);
 	}
 	ctx->event_rollover = resch.next_rollover;
diff --git a/src/knot/zone/timers.c b/src/knot/zone/timers.c
index 886039a9e9c67bc04523bebf9b938d9150c7a0c2..fff69fdd1b95d697d155ff454e89233f7f0ceb46 100644
--- a/src/knot/zone/timers.c
+++ b/src/knot/zone/timers.c
@@ -54,8 +54,7 @@ enum timer_id {
 	TIMER_LAST_REFRESH,
 	TIMER_NEXT_REFRESH,
 	TIMER_LAST_RESALT,
-	TIMER_NEXT_DS_CHECK,
-	TIMER_NEXT_DS_PUSH,
+	TIMER_NEXT_PARENT_DS_Q
 };
 
 #define TIMER_SIZE (sizeof(uint8_t) + sizeof(uint64_t))
@@ -79,13 +78,12 @@ static int deserialize_timers(zone_timers_t *timers_ptr,
 		uint8_t id = wire_ctx_read_u8(&wire);
 		uint64_t value = wire_ctx_read_u64(&wire);
 		switch (id) {
-		case TIMER_SOA_EXPIRE:    timers.soa_expire = value; break;
-		case TIMER_LAST_FLUSH:    timers.last_flush = value; break;
-		case TIMER_LAST_REFRESH:  timers.last_refresh = value; break;
-		case TIMER_NEXT_REFRESH:  timers.next_refresh = value; break;
-		case TIMER_LAST_RESALT:   timers.last_resalt = value; break;
-		case TIMER_NEXT_DS_CHECK: timers.next_ds_check = value; break;
-		case TIMER_NEXT_DS_PUSH:  timers.next_ds_push = value; break;
+		case TIMER_SOA_EXPIRE:       timers.soa_expire = value; break;
+		case TIMER_LAST_FLUSH:       timers.last_flush = value; break;
+		case TIMER_LAST_REFRESH:     timers.last_refresh = value; break;
+		case TIMER_NEXT_REFRESH:     timers.next_refresh = value; break;
+		case TIMER_LAST_RESALT:      timers.last_resalt = value; break;
+		case TIMER_NEXT_PARENT_DS_Q: timers.next_parent_ds_q = value; break;
 		default:                 break; // ignore
 		}
 	}
@@ -104,14 +102,13 @@ static void txn_write_timers(knot_lmdb_txn_t *txn, const knot_dname_t *zone,
                              const zone_timers_t *timers)
 {
 	MDB_val k = { knot_dname_size(zone), (void *)zone };
-	MDB_val v = knot_lmdb_make_key("BLBLBLBLBLBLBL",
-		TIMER_SOA_EXPIRE,    (uint64_t)timers->soa_expire,
-		TIMER_LAST_FLUSH,    (uint64_t)timers->last_flush,
-		TIMER_LAST_REFRESH,  (uint64_t)timers->last_refresh,
-		TIMER_NEXT_REFRESH,  (uint64_t)timers->next_refresh,
-		TIMER_LAST_RESALT,   (uint64_t)timers->last_resalt,
-		TIMER_NEXT_DS_CHECK, (uint64_t)timers->next_ds_check,
-		TIMER_NEXT_DS_PUSH,  (uint64_t)timers->next_ds_push);
+	MDB_val v = knot_lmdb_make_key("BLBLBLBLBLBL",
+		TIMER_SOA_EXPIRE,       (uint64_t)timers->soa_expire,
+		TIMER_LAST_FLUSH,       (uint64_t)timers->last_flush,
+		TIMER_LAST_REFRESH,     (uint64_t)timers->last_refresh,
+		TIMER_NEXT_REFRESH,     (uint64_t)timers->next_refresh,
+		TIMER_LAST_RESALT,      (uint64_t)timers->last_resalt,
+		TIMER_NEXT_PARENT_DS_Q, (uint64_t)timers->next_parent_ds_q);
 	knot_lmdb_insert(txn, &k, &v);
 	free(v.mv_data);
 }
diff --git a/src/knot/zone/timers.h b/src/knot/zone/timers.h
index 62ab9f4f4b9fd7aab36baa69239d4c7e77e530ab..5fd5b003ce09b0c089035eae0655eab597d6c7c6 100644
--- a/src/knot/zone/timers.h
+++ b/src/knot/zone/timers.h
@@ -30,9 +30,8 @@ struct zone_timers {
 	time_t last_flush;       //!< Last zone file synchronization.
 	time_t last_refresh;     //!< Last successful zone refresh attempt.
 	time_t next_refresh;     //!< Next zone refresh attempt.
-	time_t last_resalt;      //!< Last NSEC3 resalt.
-	time_t next_ds_check;    //!< Next parent DS check.
-	time_t next_ds_push;     //!< Next DDNS to parent zone with updated DS record.
+	time_t last_resalt;      //!< Last NSEC3 resalt
+	time_t next_parent_ds_q; //!< Next parent ds query
 };
 
 typedef struct zone_timers zone_timers_t;
diff --git a/tests-extra/tests/dnssec/ds_push/data/com.zone b/tests-extra/tests/dnssec/ds_push/data/com.zone
deleted file mode 100644
index 34859ad30ceedf225a754e4ac78f928ccb8ad156..0000000000000000000000000000000000000000
--- a/tests-extra/tests/dnssec/ds_push/data/com.zone
+++ /dev/null
@@ -1,6 +0,0 @@
-$ORIGIN com.
-$TTL 1200
-
-@ SOA ns admin 20110100 7 7 16 600
-ns AAAA ::0
-
diff --git a/tests-extra/tests/dnssec/ds_push/data/example.com.zone b/tests-extra/tests/dnssec/ds_push/data/example.com.zone
deleted file mode 100644
index ecd27e06e967ddb34a7420fd99137c0eec1dbdb2..0000000000000000000000000000000000000000
--- a/tests-extra/tests/dnssec/ds_push/data/example.com.zone
+++ /dev/null
@@ -1,9 +0,0 @@
-example.com.        	3	SOA	dns1.example.com. hostmaster.example.com. 2010111227 21600 3600 604800 3
-example.com.        	0	NS	dns1.example.com.
-example.com.        	2	MX	10 mail.example.com.
-dns1.example.com.   	4	A	192.0.2.1
-dns1.example.com.   	3	AAAA	2001:db8::1
-foo.example.com.    	5	A	192.0.2.4
-mail.example.com.   	3	A	192.0.2.3
-mail.example.com.   	1	AAAA	2001:db8::3
-
diff --git a/tests-extra/tests/dnssec/ds_push/test.py b/tests-extra/tests/dnssec/ds_push/test.py
deleted file mode 100644
index 62f81c9357956902456b4ad1d30f8d33a43da823..0000000000000000000000000000000000000000
--- a/tests-extra/tests/dnssec/ds_push/test.py
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/env python3
-
-"""
-Check of automatic KSK rollover with DS push.
-"""
-
-import collections
-import os
-import shutil
-import datetime
-import subprocess
-from subprocess import check_call
-
-from dnstest.utils import *
-from dnstest.keys import Keymgr
-from dnstest.test import Test
-
-def pregenerate_key(server, zone, alg):
-    class a_class_with_name:
-        def __init__(self, name):
-            self.name = name
-
-    server.gen_key(a_class_with_name("notexisting.zone."), ksk=True, alg=alg,
-                   addtopolicy=zone[0].name)
-
-# check zone if keys are present and used for signing
-def check_zone(server, zone, dnskeys, dnskey_rrsigs, cdnskeys, soa_rrsigs, msg):
-    qdnskeys = server.dig("example.com", "DNSKEY", bufsize=4096)
-    found_dnskeys = qdnskeys.count("DNSKEY")
-
-    qdnskeyrrsig = server.dig("example.com", "DNSKEY", dnssec=True, bufsize=4096)
-    found_rrsigs = qdnskeyrrsig.count("RRSIG")
-
-    qcdnskey = server.dig("example.com", "CDNSKEY", bufsize=4096)
-    found_cdnskeys = qcdnskey.count("CDNSKEY")
-
-    qsoa = server.dig("example.com", "SOA", dnssec=True, bufsize=4096)
-    found_soa_rrsigs = qsoa.count("RRSIG")
-
-    check_log("DNSKEYs: %d (expected %d)" % (found_dnskeys, dnskeys));
-    check_log("RRSIGs: %d (expected %d)" % (found_soa_rrsigs, soa_rrsigs));
-    check_log("DNSKEY-RRSIGs: %d (expected %d)" % (found_rrsigs, dnskey_rrsigs));
-    check_log("CDNSKEYs: %d (expected %d)" % (found_cdnskeys, cdnskeys));
-
-    if found_dnskeys != dnskeys:
-        set_err("BAD DNSKEY COUNT: " + msg)
-        detail_log("!DNSKEYs not published and activated as expected: " + msg)
-
-    if found_soa_rrsigs != soa_rrsigs:
-        set_err("BAD RRSIG COUNT: " + msg)
-        detail_log("!RRSIGs not published and activated as expected: " + msg)
-
-    if found_rrsigs != dnskey_rrsigs:
-        set_err("BAD DNSKEY RRSIG COUNT: " + msg)
-        detail_log("!RRSIGs not published and activated as expected: " + msg)
-
-    if found_cdnskeys != cdnskeys:
-        set_err("BAD CDNSKEY COUNT: " + msg)
-        detail_log("!CDNSKEYs not published and activated as expected: " + msg)
-
-    detail_log(SEP)
-
-    # Valgrind delay breaks the timing!
-    if not server.valgrind:
-        server.zone_backup(zone, flush=True)
-        server.zone_verify(zone)
-
-def wait_for_rrsig_count(t, server, rrtype, rrsig_count, timeout):
-    rtime = 0
-    while True:
-        qdnskeyrrsig = server.dig("example.com", rrtype, dnssec=True, bufsize=4096)
-        found_rrsigs = qdnskeyrrsig.count("RRSIG")
-        if found_rrsigs == rrsig_count:
-            break
-        rtime = rtime + 1
-        t.sleep(1)
-        if rtime > timeout:
-            break
-
-def wait_for_dnskey_count(t, server, dnskey_count, timeout):
-    rtime = 0
-    while True:
-        qdnskeyrrsig = server.dig("example.com", "DNSKEY", dnssec=True, bufsize=4096)
-        found_dnskeys = qdnskeyrrsig.count("DNSKEY")
-        if found_dnskeys == dnskey_count:
-            break
-        rtime = rtime + 1
-        t.sleep(1)
-        if rtime > timeout:
-            break
-
-def watch_ksk_rollover(t, server, zone, before_keys, after_keys, total_keys, desc, set_ksk_lifetime):
-    check_zone(server, zone, before_keys, 1, 1, 1, desc + ": initial keys")
-    orig_ksk_lifetime = server.dnssec(zone).ksk_lifetime
-
-    server.dnssec(zone).ksk_lifetime = set_ksk_lifetime if set_ksk_lifetime > 0 else orig_ksk_lifetime
-    server.gen_confile()
-    server.reload()
-
-    wait_for_dnskey_count(t, server, total_keys, 20)
-
-    t.sleep(3)
-    check_zone(server, zone, total_keys, 1, 1, 1, desc + ": published new")
-
-    server.dnssec(zone).ksk_lifetime = orig_ksk_lifetime
-    server.gen_confile()
-    server.reload()
-
-    wait_for_rrsig_count(t, server, "DNSKEY", 2, 20)
-    check_zone(server, zone, total_keys, 2, 1, 1 if before_keys > 1 else 2, desc + ": both keys active")
-
-    wait_for_rrsig_count(t, server, "DNSKEY", 1, 20)
-    check_zone(server, zone, total_keys, 1, 1, 1, desc + ": old key retired")
-
-    wait_for_dnskey_count(t, server, after_keys, 20)
-    check_zone(server, zone, after_keys, 1, 1, 1, desc + ": old key removed")
-
-t = Test(tsig=False)
-
-parent = t.server("knot")
-parent_zone = t.zone("com.", storage=".")
-t.link(parent_zone, parent, ddns=True)
-
-parent.dnssec(parent_zone).enable = True
-
-child = t.server("knot")
-child_zone = t.zone("example.com.", storage=".")
-t.link(child_zone, child)
-
-child.zonefile_sync = 24 * 60 * 60
-
-child.dnssec(child_zone).enable = True
-child.dnssec(child_zone).manual = False
-child.dnssec(child_zone).alg = "ECDSAP256SHA256"
-child.dnssec(child_zone).dnskey_ttl = 2
-child.dnssec(child_zone).zsk_lifetime = 99999
-child.dnssec(child_zone).ksk_lifetime = 300 # this can be possibly left also infinity
-child.dnssec(child_zone).propagation_delay = 11
-child.dnssec(child_zone).ksk_sbm_check = [ parent ]
-child.dnssec(child_zone).ksk_sbm_check_interval = 2
-child.dnssec(child_zone).ds_push = parent
-child.dnssec(child_zone).ksk_shared = True
-child.dnssec(child_zone).cds_publish = "always"
-
-# parameters
-ZONE = "example.com."
-
-#t.start()
-t.generate_conf()
-parent.start()
-t.sleep(2)
-child.start()
-child.zone_wait(child_zone)
-
-t.sleep(5)
-
-pregenerate_key(child, child_zone, "ECDSAP256SHA256")
-watch_ksk_rollover(t, child, child_zone, 2, 2, 3, "KSK rollover", 27)
-
-t.end()
diff --git a/tests-extra/tools/dnstest/server.py b/tests-extra/tools/dnstest/server.py
index b54489ed202ca1c078e657c39b5deba3307dc9ac..079db0b22cdc131d0e1a5c7371cabb6eeb57d36b 100644
--- a/tests-extra/tools/dnstest/server.py
+++ b/tests-extra/tools/dnstest/server.py
@@ -58,7 +58,6 @@ class ZoneDnssec(object):
         self.nsec3_salt_len = None
         self.ksk_sbm_check = []
         self.ksk_sbm_check_interval = None
-        self.ds_push = None
         self.ksk_shared = None
         self.cds_publish = None
         self.offline_ksk = None
@@ -1117,7 +1116,7 @@ class Knot(Server):
                     if slave.tsig:
                         s.item_str("key", slave.tsig.name)
                     servers.add(slave.name)
-            for parent in z.dnssec.ksk_sbm_check + [ z.dnssec.ds_push ] if z.dnssec.ds_push else z.dnssec.ksk_sbm_check:
+            for parent in z.dnssec.ksk_sbm_check:
                 if parent.name not in servers:
                     if not have_remote:
                         s.begin("remote")
@@ -1225,8 +1224,6 @@ class Knot(Server):
             self._str(s, "nsec3-salt-length", z.dnssec.nsec3_salt_len)
             if len(z.dnssec.ksk_sbm_check) > 0:
                 s.item("ksk-submission", z.name)
-            if z.dnssec.ds_push:
-                self._str(s, "ds-push", z.dnssec.ds_push.name)
             self._bool(s, "ksk-shared", z.dnssec.ksk_shared)
             self._str(s, "cds-cdnskey-publish", z.dnssec.cds_publish)
             self._str(s, "offline-ksk", z.dnssec.offline_ksk)
diff --git a/tests/knot/test_zone_timers.c b/tests/knot/test_zone_timers.c
index f364155b89d25607e382af4beb3d0cab916320dd..849081be3aadc1a376b2b6eb81b4b27dd98a5f3e 100644
--- a/tests/knot/test_zone_timers.c
+++ b/tests/knot/test_zone_timers.c
@@ -31,21 +31,9 @@ static const zone_timers_t MOCK_TIMERS = {
 	.next_refresh = 1474559960,
 	.last_flush = 1,
 	.last_resalt = 2,
-	.next_ds_check = 1474559961,
-	.next_ds_push = 1474559962,
+	.next_parent_ds_q = 0,
 };
 
-static bool timers_eq(const zone_timers_t *a, const zone_timers_t *b)
-{
-	return a->soa_expire == b->soa_expire &&
-	       a->last_refresh == b->last_refresh &&
-	       a->next_refresh == b->next_refresh &&
-	       a->last_flush == b->last_flush &&
-	       a->last_resalt == b->last_resalt &&
-	       a->next_ds_check == b->next_ds_check &&
-	       a->next_ds_push == b->next_ds_push;
-}
-
 static bool keep_all(const knot_dname_t *zone, void *data)
 {
 	return true;
@@ -56,6 +44,14 @@ static bool remove_all(const knot_dname_t *zone, void *data)
 	return false;
 }
 
+static bool timers_eq(const zone_timers_t *a, const zone_timers_t *b)
+{
+	return a->soa_expire == b->soa_expire &&
+	       a->last_refresh == b->last_refresh &&
+	       a->next_refresh == b->next_refresh &&
+	       a->last_flush == b->last_flush;
+}
+
 int main(int argc, char *argv[])
 {
 	plan_lazy();
@@ -87,7 +83,9 @@ int main(int argc, char *argv[])
 	memset(&timers, 0, sizeof(timers));
 	ret = zone_timers_read(db, zone, &timers);
 	ok(ret == KNOT_EOK, "zone_timers_read()");
-	ok(timers_eq(&timers, &MOCK_TIMERS), "inconsistent timers");
+	ok(timers_eq(&timers, &MOCK_TIMERS), "timers unmalformed (%u == %u, %ld == %ld etc.)",
+	   timers.soa_expire, MOCK_TIMERS.soa_expire, (long)timers.last_refresh,
+	   (long)MOCK_TIMERS.last_refresh);
 
 	// Sweep none
 	ret = zone_timers_sweep(db, keep_all, NULL);