diff --git a/doc/man/keymgr.8in b/doc/man/keymgr.8in
index af5225cfa2b5ce05870f68d23bb3e666fb315497..091a265f68d28f0a7d691fcef36e50e0fc4e474d 100644
--- a/doc/man/keymgr.8in
+++ b/doc/man/keymgr.8in
@@ -32,7 +32,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 ..
 .SH SYNOPSIS
 .sp
-\fBkeymgr\fP [\fIconfig_option\fP \fIconfig_argument\fP] [\fIoption\fP\&...] \fIzone\fP \fIcommand\fP \fIargument\fP\&...
+\fBkeymgr\fP [\fIconfig_option\fP \fIconfig_argument\fP] [\fIoption\fP\&...] \fIzone_name\fP \fIcommand\fP \fIargument\fP\&...
 .sp
 \fBkeymgr\fP [\fIconfig_option\fP \fIconfig_argument\fP] \fB\-l\fP
 .sp
diff --git a/doc/man/kzonesign.1in b/doc/man/kzonesign.1in
index f1631537390ca7be5d265e334fd1e2fd1a25ce1d..693b17a560e616a60137db0ae6f35258bd26e5cd 100644
--- a/doc/man/kzonesign.1in
+++ b/doc/man/kzonesign.1in
@@ -32,16 +32,24 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 ..
 .SH SYNOPSIS
 .sp
-\fBkzonesign\fP [\fIoptions\fP] \fB\-c\fP \fIconf_file\fP \fIzone_name\fP
+\fBkzonesign\fP [\fIconfig_option\fP \fIconfig_argument\fP] [\fIoptions\fP] \fIzone_name\fP
 .SH DESCRIPTION
 .sp
 This utility reads the zone\(aqs zone file, signs the zone according to given
 configuration, and writes the signed zone file back.
-.SS Options
+.SS Config options
 .INDENT 0.0
 .TP
-\fB\-c\fP, \fB\-\-config\fP \fIconf_file\fP
-Knot DNS configuration file (same as for knotd).
+\fB\-c\fP, \fB\-\-config\fP \fIfile\fP
+Use a textual configuration file (default is \fB@config_dir@/knot.conf\fP).
+.TP
+\fB\-C\fP, \fB\-\-confdb\fP \fIdirectory\fP
+Use a binary configuration database directory (default is \fB@storage_dir@/confdb\fP).
+The default configuration database, if exists, has a preference to the default
+configuration file.
+.UNINDENT
+.SS Options
+.INDENT 0.0
 .TP
 \fB\-o\fP, \fB\-\-outdir\fP \fIdir_name\fP
 Write the output zone file to the specified directory insted of the configured one.
diff --git a/doc/man_keymgr.rst b/doc/man_keymgr.rst
index 4955a7f8d9f0aa2c535f6555f52aabe34157d1ed..e3047bc5db77f69c696ee3545c2746ee789bc907 100644
--- a/doc/man_keymgr.rst
+++ b/doc/man_keymgr.rst
@@ -6,7 +6,7 @@ keymgr – Key management utility
 Synopsis
 --------
 
-:program:`keymgr` [*config_option* *config_argument*] [*option*...] *zone* *command* *argument*...
+:program:`keymgr` [*config_option* *config_argument*] [*option*...] *zone_name* *command* *argument*...
 
 :program:`keymgr` [*config_option* *config_argument*] **-l**
 
diff --git a/doc/man_kzonesign.rst b/doc/man_kzonesign.rst
index 81f165304889fde92cc8f3d39296c951461d3f43..44004f6c35407d0a00dcd111f47dd9530fbad24d 100644
--- a/doc/man_kzonesign.rst
+++ b/doc/man_kzonesign.rst
@@ -6,7 +6,7 @@ kzonesign – DNSSEC signing utility
 Synopsis
 --------
 
-:program:`kzonesign` [*options*] **-c** *conf_file* *zone_name*
+:program:`kzonesign` [*config_option* *config_argument*] [*options*] *zone_name*
 
 Description
 -----------
@@ -14,12 +14,20 @@ Description
 This utility reads the zone's zone file, signs the zone according to given
 configuration, and writes the signed zone file back.
 
+Config options
+..............
+
+**-c**, **--config** *file*
+  Use a textual configuration file (default is :file:`@config_dir@/knot.conf`).
+
+**-C**, **--confdb** *directory*
+  Use a binary configuration database directory (default is :file:`@storage_dir@/confdb`).
+  The default configuration database, if exists, has a preference to the default
+  configuration file.
+
 Options
 .......
 
-**-c**, **--config** *conf_file*
-  Knot DNS configuration file (same as for knotd).
-
 **-o**, **--outdir** *dir_name*
   Write the output zone file to the specified directory insted of the configured one.
 
diff --git a/src/utils/Makefile.inc b/src/utils/Makefile.inc
index 29ca9d275ad247ae1b8c508cc80ab01020f5db8e..806dab5c1199d9065f5938801e505db771adb3ad 100644
--- a/src/utils/Makefile.inc
+++ b/src/utils/Makefile.inc
@@ -158,7 +158,7 @@ kcatalogprint_SOURCES = \
 kzonecheck_CPPFLAGS    = $(libknotus_la_CPPFLAGS)
 kzonecheck_LDADD       = $(libknotd_LIBS)
 kzonesign_CPPFLAGS     = $(libknotus_la_CPPFLAGS)
-kzonesign_LDADD        = $(libknotd_LIBS)
+kzonesign_LDADD        = $(libknotd_LIBS) $(libknotus_LIBS)
 keymgr_CPPFLAGS        = $(libknotus_la_CPPFLAGS)
 keymgr_LDADD           = $(libknotd_LIBS) $(libknotus_LIBS)
 kjournalprint_CPPFLAGS = $(libknotus_la_CPPFLAGS)
diff --git a/src/utils/common/util_conf.c b/src/utils/common/util_conf.c
index 81edb9c95b0f5298dc87eb5dbd4598dfe12bdda0..2cb71525dd64b70b239762897113aee2c0a511f4 100644
--- a/src/utils/common/util_conf.c
+++ b/src/utils/common/util_conf.c
@@ -92,7 +92,7 @@ int util_conf_init_justdb(const char *db_type, const char *db_path)
 	return ret;
 }
 
-int util_conf_init_default(void)
+int util_conf_init_default(bool allow_db)
 {
 	struct stat st;
 	if (util_conf_initialized()) {
@@ -102,7 +102,8 @@ int util_conf_init_default(void)
 	} else if (stat(CONF_DEFAULT_FILE, &st) == 0) {
 		return util_conf_init_file(CONF_DEFAULT_FILE);
 	} else {
-		ERR2("couldn't initialize configuration, please provide -c, -C, or -D option\n");
+		ERR2("couldn't initialize configuration, please provide %s option\n",
+		     (allow_db ? "-c, -C, or -D" : "-c or -C"));
 		return KNOT_EINVAL;
 	}
 }
diff --git a/src/utils/common/util_conf.h b/src/utils/common/util_conf.h
index ab1bdd7f976b5beb6191952346e482683b561d5f..68767692618a8a690010b2399b80d6fc4ae15491 100644
--- a/src/utils/common/util_conf.h
+++ b/src/utils/common/util_conf.h
@@ -67,9 +67,11 @@ int util_conf_init_justdb(const char *db_type, const char *db_path);
  * \brief Initialize conf() for utilities based on existence of confDB or config
  *        file on default locations.
  *
+ * \param allow_db   Direct path to a database is allowed.
+ *
  * \return KNOT_E*
  */
-int util_conf_init_default(void);
+int util_conf_init_default(bool allow_db);
 
 /*!
  * \brief Set UID and GID of running utility process to what is configured...
diff --git a/src/utils/kcatalogprint/main.c b/src/utils/kcatalogprint/main.c
index 4ee055096a16f004681ccc4c8b754e789c14691c..33be9e9ada245bf94b006d1d28271ef2b061f7a7 100644
--- a/src/utils/kcatalogprint/main.c
+++ b/src/utils/kcatalogprint/main.c
@@ -128,7 +128,7 @@ int main(int argc, char *argv[])
 		optind++;
 	}
 
-	if (util_conf_init_default() != KNOT_EOK) {
+	if (util_conf_init_default(true) != KNOT_EOK) {
 		goto failure;
 	}
 
diff --git a/src/utils/keymgr/main.c b/src/utils/keymgr/main.c
index 030bb776292e8249c80c05af79f7ec4fe07e69bc..0f29115bd04b0cc862fe0ee805d80238cb6eb2e7 100644
--- a/src/utils/keymgr/main.c
+++ b/src/utils/keymgr/main.c
@@ -32,7 +32,7 @@
 static void print_help(void)
 {
 	printf("Usage:\n"
-	       "  %s [-c | -C | -D <path>] <zone> <command> [<argument>...]\n"
+	       "  %s [-c | -C | -D <path>] <zone_name> <command> [<argument>...]\n"
 	       "  %s [-c | -C | -D <path>] -l\n"
 	       "  %s -t <tsig_name> [<algorithm> [<bits>]]\n"
 	       "\n"
@@ -364,7 +364,7 @@ int main(int argc, char *argv[])
 		}
 	}
 
-	if (util_conf_init_default() != KNOT_EOK) {
+	if (util_conf_init_default(true) != KNOT_EOK) {
 		goto failure;
 	}
 
diff --git a/src/utils/kjournalprint/main.c b/src/utils/kjournalprint/main.c
index cbcde21f9ecca10b0cde6b61126b1202d5ed3402..fb72a98703ea4896f1feb45bececf74aced5e3eb 100644
--- a/src/utils/kjournalprint/main.c
+++ b/src/utils/kjournalprint/main.c
@@ -398,7 +398,7 @@ int main(int argc, char *argv[])
 		optind++;
 	}
 
-	if (util_conf_init_default() != KNOT_EOK) {
+	if (util_conf_init_default(true) != KNOT_EOK) {
 		goto failure;
 	}
 
diff --git a/src/utils/kzonesign/main.c b/src/utils/kzonesign/main.c
index 34a298ed9b5f1747ca704215bc849a7af7ace1e6..8921379c9ec0916d96efc0b774d16da488bf7d6a 100644
--- a/src/utils/kzonesign/main.c
+++ b/src/utils/kzonesign/main.c
@@ -17,7 +17,6 @@
 #include <getopt.h>
 #include <stdlib.h>
 
-#include "knot/conf/conf.h"
 #include "knot/dnssec/zone-events.h"
 #include "knot/updates/zone-update.h"
 #include "knot/server/server.h"
@@ -26,145 +25,67 @@
 #include "utils/common/msg.h"
 #include "utils/common/params.h"
 #include "utils/common/util_conf.h"
+#include "contrib/strtonum.h"
 
 #define PROGRAM_NAME "kzonesign"
 
-static const char *global_outdir = NULL;
-
-// copy-pasted from keymgr
-static bool init_conf(const char *confdb)
-{
-	size_t max_conf_size = (size_t)CONF_MAPSIZE * 1024 * 1024;
-
-	conf_flag_t flags = CONF_FNOHOSTNAME | CONF_FOPTMODULES;
-	if (confdb != NULL) {
-		flags |= CONF_FREADONLY;
-	}
-
-	conf_t *new_conf = NULL;
-	int ret = conf_new(&new_conf, conf_schema, confdb, max_conf_size, flags);
-	if (ret != KNOT_EOK) {
-		ERR2("failed opening configuration database %s (%s)\n",
-		     (confdb == NULL ? "" : confdb), knot_strerror(ret));
-		return false;
-	}
-	conf_update(new_conf, CONF_UPD_FNONE);
-	return true;
-}
-
 static void print_help(void)
 {
-	printf("Usage: %s [parameters] -c <conf_file> <zone_name>\n"
+	printf("Usage: %s [-c | -C <path>] [parameters] <zone_name>\n"
 	       "\n"
 	       "Parameters:\n"
+	       " -c, --config <file>      Path to a textual configuration file.\n"
+	       "                           (default %s)\n"
+	       " -C, --confdb <dir>       Path to a configuration database directory.\n"
+	       "                           (default %s)\n"
 	       " -o, --outdir <dir_name>  Output directory.\n"
 	       " -r, --rollover           Allow key rollovers and NSEC3 re-salt.\n"
 	       " -t, --time <timestamp>   Current time specification.\n"
-	       "                            (default current UNIX time)\n"
+	       "                           (default current UNIX time)\n"
 	       " -h, --help               Print the program help.\n"
 	       " -V, --version            Print the program version.\n"
 	       "\n",
-	       PROGRAM_NAME);
+	       PROGRAM_NAME, CONF_DEFAULT_FILE, CONF_DEFAULT_DBDIR);
 }
 
-int main(int argc, char *argv[])
+typedef struct {
+	const char *zone_name_str;
+	knot_dname_storage_t zone_name;
+	const char *outdir;
+	zone_sign_roll_flags_t rollover;
+	int64_t timestamp;
+} sign_params_t;
+
+static int zonesign(sign_params_t *params)
 {
-	const char *confile = NULL, *zone_str = NULL;
-	knot_dname_t *zone_name = NULL;
+	char *zonefile = NULL;
 	zone_contents_t *unsigned_conts = NULL;
 	zone_t *zone_struct = NULL;
 	zone_update_t up = { 0 };
 	server_t fake_server = { 0 };
-	zone_sign_roll_flags_t rollover = 0;
-	int64_t timestamp = 0;
 	zone_sign_reschedule_t next_sign = { 0 };
+	int ret = KNOT_ERROR;
 
-	struct option opts[] = {
-		{ "config",    required_argument, NULL, 'c' },
-		{ "outdir",    required_argument, NULL, 'o' },
-		{ "rollover",  no_argument,       NULL, 'r' },
-		{ "time",      required_argument, NULL, 't' },
-		{ "help",      no_argument,       NULL, 'h' },
-		{ "version",   no_argument,       NULL, 'V' },
-		{ NULL }
-	};
-
-	tzset();
-
-	int opt;
-	while ((opt = getopt_long(argc, argv, "c:o:rt:hV", opts, NULL)) != -1) {
-		switch (opt) {
-		case 'c':
-			confile = optarg;
-			break;
-		case 'o':
-			global_outdir = optarg;
-			break;
-		case 'r':
-			rollover = KEY_ROLL_ALLOW_ALL;
-			break;
-		case 't':
-			timestamp = atol(optarg);
-			if (timestamp <= 0) {
-				print_help();
-				return EXIT_FAILURE;
-			}
-			break;
-		case 'h':
-			print_help();
-			return EXIT_SUCCESS;
-		case 'V':
-			print_version(PROGRAM_NAME);
-			return EXIT_SUCCESS;
-		default:
-			print_help();
-			return EXIT_FAILURE;
-		}
-	}
-	if (confile == NULL || argc - optind != 1) {
-		print_help();
-		return EXIT_FAILURE;
-	}
-
-	zone_str = argv[optind];
-	zone_name = knot_dname_from_str_alloc(zone_str);
-	if (zone_name == NULL) {
-		ERR2("invalid zone name '%s'\n", zone_str);
-		return EXIT_FAILURE;
-	}
-	knot_dname_to_lower(zone_name);
-
-	if (!init_conf(NULL)) {
-		free(zone_name);
-		return EXIT_FAILURE;
-	}
-
-	int ret = conf_import(conf(), confile, true, false);
-	if (ret != KNOT_EOK) {
-		ERR2("failed opening configuration file '%s' (%s)\n",
-		     confile, knot_strerror(ret));
-		goto fail;
-	}
-
-	conf_val_t val = conf_zone_get(conf(), C_DOMAIN, zone_name);
+	conf_val_t val = conf_zone_get(conf(), C_DOMAIN, params->zone_name);
 	if (val.code != KNOT_EOK) {
-		ERR2("zone '%s' not configured\n", zone_str);
-		ret = val.code;
+		ERR2("zone '%s' not configured\n", params->zone_name_str);
+		ret = KNOT_ENOENT;
 		goto fail;
 	}
-	val = conf_zone_get(conf(), C_DNSSEC_POLICY, zone_name);
+	val = conf_zone_get(conf(), C_DNSSEC_POLICY, params->zone_name);
 	if (val.code != KNOT_EOK) {
-		WARN2("DNSSEC policy not configured for zone '%s', taking defaults\n", zone_str);
+		WARN2("DNSSEC policy not configured for zone '%s', taking defaults\n",
+		      params->zone_name_str);
 	}
 
-	zone_struct = zone_new(zone_name);
+	zone_struct = zone_new(params->zone_name);
 	if (zone_struct == NULL) {
 		ERR2("out of memory\n");
 		ret = KNOT_ENOMEM;
 		goto fail;
 	}
 
-	ret = zone_load_contents(conf(), zone_name, &unsigned_conts, false);
+	ret = zone_load_contents(conf(), params->zone_name, &unsigned_conts, false);
 	if (ret != KNOT_EOK) {
 		ERR2("failed to load zone contents (%s)\n", knot_strerror(ret));
 		goto fail;
@@ -180,10 +101,12 @@ int main(int argc, char *argv[])
 	kasp_db_ensure_init(&fake_server.kaspdb, conf());
 	zone_struct->server = &fake_server;
 
-	ret = knot_dnssec_zone_sign(&up, conf(), 0, rollover, timestamp, &next_sign);
+	ret = knot_dnssec_zone_sign(&up, conf(), 0, params->rollover,
+	                            params->timestamp, &next_sign);
 	if (ret == KNOT_DNSSEC_ENOKEY) { // exception: allow generating initial keys
-		rollover = KEY_ROLL_ALLOW_ALL;
-		ret = knot_dnssec_zone_sign(&up, conf(), 0, rollover, timestamp, &next_sign);
+		params->rollover = KEY_ROLL_ALLOW_ALL;
+		ret = knot_dnssec_zone_sign(&up, conf(), 0, params->rollover,
+		                            params->timestamp, &next_sign);
 	}
 	if (ret != KNOT_EOK) {
 		ERR2("failed to sign the zone (%s)\n", knot_strerror(ret));
@@ -191,24 +114,30 @@ int main(int argc, char *argv[])
 		goto fail;
 	}
 
-	if (global_outdir == NULL) {
-		char *zonefile = conf_zonefile(conf(), zone_name);
+	if (params->outdir == NULL) {
+		zonefile = conf_zonefile(conf(), params->zone_name);
 		ret = zonefile_write(zonefile, up.new_cont);
-		free(zonefile);
 	} else {
 		zone_contents_t *temp = zone_struct->contents;
 		zone_struct->contents = up.new_cont;
-		ret = zone_dump_to_dir(conf(), zone_struct, global_outdir);
+		ret = zone_dump_to_dir(conf(), zone_struct, params->outdir);
 		zone_struct->contents = temp;
 	}
 	zone_update_clear(&up);
 	if (ret != KNOT_EOK) {
-		ERR2("failed to flush signed zone to file (%s)\n", knot_strerror(ret));
+		if (params->outdir == NULL) {
+			ERR2("failed to update zone file '%s' (%s)\n",
+			     zonefile, knot_strerror(ret));
+		} else {
+			ERR2("failed to flush signed zone to '%s' file (%s)\n",
+			     params->outdir, knot_strerror(ret));
+
+		}
 		goto fail;
 	}
 
 	printf("Next signing: %"KNOT_TIME_PRINTF"\n", next_sign.next_sign);
-	if (rollover) {
+	if (params->rollover) {
 		printf("Next roll-over: %"KNOT_TIME_PRINTF"\n", next_sign.next_rollover);
 		if (next_sign.next_nsec3resalt) {
 			printf("Next NSEC3 re-salt: %"KNOT_TIME_PRINTF"\n", next_sign.next_nsec3resalt);
@@ -223,7 +152,92 @@ fail:
 		knot_lmdb_deinit(&fake_server.kaspdb);
 	}
 	zone_free(&zone_struct);
-	conf_free(conf());
-	free(zone_name);
-	return ret == KNOT_EOK ? EXIT_SUCCESS : EXIT_FAILURE;
+	free(zonefile);
+
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	sign_params_t params = { 0 };
+
+	struct option opts[] = {
+		{ "config",    required_argument, NULL, 'c' },
+		{ "confdb",    required_argument, NULL, 'C' },
+		{ "outdir",    required_argument, NULL, 'o' },
+		{ "rollover",  no_argument,       NULL, 'r' },
+		{ "time",      required_argument, NULL, 't' },
+		{ "help",      no_argument,       NULL, 'h' },
+		{ "version",   no_argument,       NULL, 'V' },
+		{ NULL }
+	};
+
+	tzset();
+
+	int opt = 0;
+	while ((opt = getopt_long(argc, argv, "c:C:o:rt:hV", opts, NULL)) != -1) {
+		switch (opt) {
+		case 'c':
+			if (util_conf_init_file(optarg) != KNOT_EOK) {
+				goto failure;
+			}
+			break;
+		case 'C':
+			if (util_conf_init_confdb(optarg) != KNOT_EOK) {
+				goto failure;
+			}
+			break;
+		case 'o':
+			params.outdir = optarg;
+			break;
+		case 'r':
+			params.rollover = KEY_ROLL_ALLOW_ALL;
+			break;
+		case 't':
+			; uint32_t num = 0;
+			if (str_to_u32(optarg, &num) != KNOT_EOK || num == 0) {
+				print_help();
+				goto failure;
+			}
+			params.timestamp = num;
+			break;
+		case 'h':
+			print_help();
+			goto success;
+		case 'V':
+			print_version(PROGRAM_NAME);
+			goto success;
+		default:
+			print_help();
+			goto failure;
+		}
+	}
+	if (argc - optind != 1) {
+		ERR2("missing zone name\n");
+		print_help();
+		goto failure;
+	}
+	params.zone_name_str = argv[optind];
+	if (knot_dname_from_str(params.zone_name, params.zone_name_str,
+	                        sizeof(params.zone_name)) == NULL) {
+		ERR2("invalid zone name '%s'\n", params.zone_name_str);
+		print_help();
+		goto failure;
+	}
+	knot_dname_to_lower(params.zone_name);
+
+	if (util_conf_init_default(false) != KNOT_EOK) {
+		goto failure;
+	}
+
+	if (zonesign(&params) != KNOT_EOK) {
+		goto failure;
+	}
+
+success:
+	util_conf_deinit();
+	return EXIT_SUCCESS;
+failure:
+	util_conf_deinit();
+	return EXIT_FAILURE;
 }