diff --git a/samples/knot.conf.sample b/samples/knot.conf.sample
index 40636a5525b9ba4b27320c5944bbfbf73bd4e91f..23b1079455610d81ee12349d115253fd6641561e 100644
--- a/samples/knot.conf.sample
+++ b/samples/knot.conf.sample
@@ -42,6 +42,14 @@ system {
 # Section 'zones' contains information about zones to be served.
 zones {
 
+  # Shared options for all listed zones
+  #
+
+  # Enable semantic checks for all zones (if 'on')
+  # Possible values: on|off
+  # Default value: off
+  semantic-checks off;
+
   # Zone entry
   #
   # Format: <zone-name> { file "<path-to-zone-file>"; }
@@ -50,6 +58,11 @@ zones {
     #   it is considered relative to the current directory from which the server
     #   was started.
     file "samples/example.com.zone";
+
+    # Enable zone semantic checks
+    # Possible values: on|off
+    # Default value: off
+    semantic-checks on;
   }
 }
 
diff --git a/src/common/slab/alloc-common.h b/src/common/slab/alloc-common.h
index 80f1331437288b388298223d7710e5b617852afe..4ce97172c95de43b56d109dc724ffb682f433fab 100644
--- a/src/common/slab/alloc-common.h
+++ b/src/common/slab/alloc-common.h
@@ -17,7 +17,7 @@
 //#define MEM_DEBUG
 //#define MEM_NOSLAB
 //#define MEM_POISON
-//#define MEM_SLAB_CAP 3   // Cap slab_cache empty slab count (undefined = inf)
+#define MEM_SLAB_CAP 5   // Cap slab_cache empty slab count (undefined = inf)
 #define MEM_COLORING       // Slab cache coloring
 //#define MEM_SLAB_DEPOT     // Use slab depot for slab caching (not thread-safe)
 
diff --git a/src/dnslib/zone-dump.c b/src/dnslib/zone-dump.c
index b5358d8dd954a4b48126e5d1002f347790b86a6e..f003b9abf3784f727b500948eaa26a44c38d9093 100644
--- a/src/dnslib/zone-dump.c
+++ b/src/dnslib/zone-dump.c
@@ -323,7 +323,7 @@ static void log_error_from_node(err_handler_t *handler,
 		fprintf(stderr, "%s", error_messages[-error]);
 		free(name);
 	} else {
-		fprintf(stderr, "Total number of errors is: %d for error: %s:",
+		fprintf(stderr, "Total number of errors is: %d for error: %s",
 			handler->errors[-error],
 			error_messages[-error]);
 	}
@@ -1932,7 +1932,7 @@ static void log_cyclic_errors_in_zone(err_handler_t *handler,
 }
 
 int dnslib_zdump_binary(dnslib_zone_t *zone, const char *filename,
-			char do_checks, const char *sfilename)
+			int do_checks, const char *sfilename)
 {
 	FILE *f;
 
diff --git a/src/dnslib/zone-dump.h b/src/dnslib/zone-dump.h
index b14fe5001d235dea10e5a69642dbeb7115194e29..a5941318cf8376426958f9cca04bea210b23439e 100644
--- a/src/dnslib/zone-dump.h
+++ b/src/dnslib/zone-dump.h
@@ -36,7 +36,7 @@ enum {
  * \retval DNSLIB_EBADARG if the file cannot be opened for writing.
  */
 int dnslib_zdump_binary(dnslib_zone_t *zone, const char *filename,
-			char do_checks, const char *sfilename);
+			int do_checks, const char *sfilename);
 
 #endif /* _DNSLIB_ZONEDUMP_H_ */
 
diff --git a/src/dnslib/zone-load.c b/src/dnslib/zone-load.c
index 934bc2ed4df5a190003aff6af8a3c6b4665d177b..e4cbb3f1a24991393b07fc799effc0034734dc0e 100644
--- a/src/dnslib/zone-load.c
+++ b/src/dnslib/zone-load.c
@@ -86,9 +86,6 @@ static inline int fread_safe(void *dst, size_t size, size_t n, FILE *fp)
 
 enum { DNAME_MAX_WIRE_LENGTH = 256 };
 
-//TODO move to parameters
-static dnslib_dname_t **id_array;
-
 /*!
  * \brief Helper function. Frees rdata items and temporary array of items.
  *
@@ -115,7 +112,8 @@ static void load_rdata_purge(dnslib_rdata_t *rdata,
  *
  * \return Pointer to read and created rdata on success, NULL otherwise.
  */
-static dnslib_rdata_t *dnslib_load_rdata(uint16_t type, FILE *f)
+static dnslib_rdata_t *dnslib_load_rdata(uint16_t type, FILE *f,
+                                         dnslib_dname_t **id_array)
 {
 	dnslib_rdata_t *rdata;
 
@@ -270,7 +268,7 @@ static dnslib_rdata_t *dnslib_load_rdata(uint16_t type, FILE *f)
  *
  * \return pointer to created and read RRSIG on success, NULL otherwise.
  */
-static dnslib_rrset_t *dnslib_load_rrsig(FILE *f)
+static dnslib_rrset_t *dnslib_load_rrsig(FILE *f, dnslib_dname_t **id_array)
 {
 	dnslib_rrset_t *rrsig;
 
@@ -310,7 +308,8 @@ static dnslib_rrset_t *dnslib_load_rrsig(FILE *f)
 	debug_dnslib_zload("loading %d rdata entries\n", rdata_count);
 
 	for (int i = 0; i < rdata_count; i++) {
-		tmp_rdata = dnslib_load_rdata(DNSLIB_RRTYPE_RRSIG, f);
+		tmp_rdata = dnslib_load_rdata(DNSLIB_RRTYPE_RRSIG, f,
+		                              id_array);
 		if (tmp_rdata) {
 			dnslib_rrset_add_rdata(rrsig, tmp_rdata);
 		} else {
@@ -329,7 +328,7 @@ static dnslib_rrset_t *dnslib_load_rrsig(FILE *f)
  *
  * \return pointer to created and read RRSet on success, NULL otherwise.
  */
-static dnslib_rrset_t *dnslib_load_rrset(FILE *f)
+static dnslib_rrset_t *dnslib_load_rrset(FILE *f, dnslib_dname_t **id_array)
 {
 	dnslib_rrset_t *rrset;
 
@@ -363,7 +362,8 @@ static dnslib_rrset_t *dnslib_load_rrset(FILE *f)
 	dnslib_rdata_t *tmp_rdata;
 
 	for (int i = 0; i < rdata_count; i++) {
-		tmp_rdata = dnslib_load_rdata(rrset->type, f);
+		tmp_rdata = dnslib_load_rdata(rrset->type, f,
+		                              id_array);
 		if (tmp_rdata) {
 			dnslib_rrset_add_rdata(rrset, tmp_rdata);
 		} else {
@@ -375,7 +375,7 @@ static dnslib_rrset_t *dnslib_load_rrset(FILE *f)
 	dnslib_rrset_t *tmp_rrsig = NULL;
 
 	if (rrsig_count) {
-		tmp_rrsig = dnslib_load_rrsig(f);
+		tmp_rrsig = dnslib_load_rrsig(f, id_array);
 	}
 
 	rrset->rrsigs = tmp_rrsig;
@@ -390,7 +390,7 @@ static dnslib_rrset_t *dnslib_load_rrset(FILE *f)
  *
  * \return Pointer to created and read node on success, NULL otherwise.
  */
-static dnslib_node_t *dnslib_load_node(FILE *f)
+static dnslib_node_t *dnslib_load_node(FILE *f, dnslib_dname_t **id_array)
 {
 	uint8_t dname_size = 0;
 	uint8_t flags = 0;
@@ -509,7 +509,7 @@ static dnslib_node_t *dnslib_load_node(FILE *f)
 	dnslib_rrset_t *tmp_rrset;
 
 	for (int i = 0; i < rrset_count; i++) {
-		if ((tmp_rrset = dnslib_load_rrset(f)) == NULL) {
+		if ((tmp_rrset = dnslib_load_rrset(f, id_array)) == NULL) {
 			dnslib_node_free(&node, 1);
 			//TODO what else to free?
 			fprintf(stderr, "zone: Could not load rrset.\n");
@@ -659,6 +659,16 @@ zloader_t *dnslib_zload_open(const char *filename)
 	return zl;
 }
 
+static void cleanup_id_array(dnslib_dname_t **id_array,
+                             const uint from, const uint to)
+{
+	for (uint i = from; i < to; i++) {
+		dnslib_dname_free(&(id_array[i]));
+	}
+
+	free(id_array);
+}
+
 dnslib_zone_t *dnslib_zload_load(zloader_t *loader)
 {
 	if (!loader) {
@@ -687,12 +697,14 @@ dnslib_zone_t *dnslib_zload_load(zloader_t *loader)
 		return NULL;
 	}
 
-	debug_dnslib_zload("authorative nodes: %u\n", auth_node_count);
+	debug_dnslib_zload("authoritative nodes: %u\n", auth_node_count);
 
-	id_array =
+	dnslib_dname_t **id_array =
 		malloc(sizeof(dnslib_dname_t *) *
 		(node_count + nsec3_node_count + 1));
 
+	CHECK_ALLOC_LOG(id_array, NULL);
+
 	debug_dnslib_zload("loading %u nodes\n", node_count);
 
 	for (uint i = 1; i < (node_count + nsec3_node_count + 1); i++) {
@@ -700,17 +712,23 @@ dnslib_zone_t *dnslib_zload_load(zloader_t *loader)
 		id_array[i]->node = dnslib_node_new(NULL, NULL);
 	}
 
-	dnslib_node_t *apex = dnslib_load_node(f);
+	dnslib_node_t *apex = dnslib_load_node(f, id_array);
 
 	if (!apex) {
 		fprintf(stderr, "zone: Could not load apex node (in %s)\n",
 			loader->filename);
+		cleanup_id_array(id_array, 1,
+		                 node_count + nsec3_node_count + 1);
 		return NULL;
 	}
 
 	dnslib_zone_t *zone = dnslib_zone_new(apex, auth_node_count);
 
-	assert(zone != NULL);
+	if (zone == NULL) {
+		cleanup_id_array(id_array, 1,
+		                 node_count + nsec3_node_count + 1);
+		return NULL;
+	}
 
 	apex->prev = NULL;
 
@@ -719,7 +737,7 @@ dnslib_zone_t *dnslib_zload_load(zloader_t *loader)
 	last_node = apex;
 
 	for (uint i = 1; i < node_count; i++) {
-		tmp_node = dnslib_load_node(f);
+		tmp_node = dnslib_load_node(f, id_array);
 
 		if (tmp_node != NULL) {
 			if (dnslib_zone_add_node(zone, tmp_node) != 0) {
@@ -755,14 +773,17 @@ dnslib_zone_t *dnslib_zload_load(zloader_t *loader)
 	dnslib_node_t *nsec3_first = NULL;
 
 	if (nsec3_node_count > 0) {
-		nsec3_first = dnslib_load_node(f);
+		nsec3_first = dnslib_load_node(f, id_array);
 
 		assert(nsec3_first != NULL);
 
 		if (dnslib_zone_add_nsec3_node(zone, nsec3_first) != 0) {
 			fprintf(stderr, "!! cannot add first nsec3 node, "
 				"exiting.\n");
-			dnslib_zone_deep_free(&zone, 0);
+			dnslib_zone_deep_free(&zone, 1);
+			free(id_array);
+			/* TODO this will leak dnames from id_array that were
+			 * not assigned. */
 			return NULL;
 		}
 
@@ -772,7 +793,7 @@ dnslib_zone_t *dnslib_zload_load(zloader_t *loader)
 	}
 
 	for (uint i = 1; i < nsec3_node_count; i++) {
-		tmp_node = dnslib_load_node(f);
+		tmp_node = dnslib_load_node(f, id_array);
 
 		if (tmp_node != NULL) {
 			if (dnslib_zone_add_nsec3_node(zone, tmp_node) != 0) {
@@ -789,6 +810,8 @@ dnslib_zone_t *dnslib_zload_load(zloader_t *loader)
 		}
 	}
 
+	free(id_array);
+
 	if (nsec3_node_count) {
 		assert(nsec3_first->prev == NULL);
 		nsec3_first->prev = last_node;
diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l
index 67b93692bd18d2414045bd5d9f77a807ad95e7b4..3e36ca75bca0990ae3e770c27e079d5f63ec6df3 100644
--- a/src/knot/conf/cf-lex.l
+++ b/src/knot/conf/cf-lex.l
@@ -67,6 +67,7 @@ key                  return KEY;
 
 zones                return ZONES;
 file                 return FILENAME;
+semantic-checks      return SEMANTIC_CHECKS;
 
 interfaces           return INTERFACES;
 address              return ADDRESS;
@@ -87,6 +88,14 @@ notice               { cf_lval.i = LOG_MASK(LOG_NOTICE); return LOG_LEVEL; }
 warning              { cf_lval.i = LOG_MASK(LOG_WARNING); return LOG_LEVEL; }
 error                { cf_lval.i = LOG_MASK(LOG_ERR); return LOG_LEVEL; }
 
+on|off {
+  cf_lval.i = 0;
+  if (strcmp(yytext, "on") == 0) {
+    cf_lval.i = 1;
+  }
+  return BOOL;
+}
+
 {DIGIT}+ {
   cf_lval.i = atoi(yytext);
   return NUM;
diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y
index 3c657c4a0634995cececc76c9d6e435c3325a746..2d3593efeba0d3670b2a91f84bb993009f0ef7b9 100644
--- a/src/knot/conf/cf-parse.y
+++ b/src/knot/conf/cf-parse.y
@@ -35,11 +35,13 @@ static conf_log_map_t *this_logmap = 0;
 %token END INVALID_TOKEN
 %token <t> TEXT
 %token <i> NUM
+%token <i> BOOL
 
 %token SYSTEM IDENTITY VERSION STORAGE KEY
 %token <alg> TSIG_ALGO_NAME
 
 %token ZONES FILENAME
+%token SEMANTIC_CHECKS
 
 %token INTERFACES ADDRESS PORT
 %token <t> IPA
@@ -112,6 +114,7 @@ system:
 zone_start: TEXT {
    this_zone = malloc(sizeof(conf_zone_t));
    memset(this_zone, 0, sizeof(conf_zone_t));
+   this_zone->enable_checks = -1; // Default policy applies
    this_zone->name = $1;
 
    // Append mising dot to ensure FQDN
@@ -126,24 +129,27 @@ zone_start: TEXT {
                                                   nlen + 1,
                                                   0);
    if (dn == 0) {
+     free(this_zone->name);
+     free(this_zone);
      cf_error("invalid zone origin");
    } else {
      dnslib_dname_free(&dn);
+     add_tail(&new_config->zones, &this_zone->n);
+     ++new_config->zones_count;
    }
-
-   add_tail(&new_config->zones, &this_zone->n);
-   ++new_config->zones_count;
  }
  ;
 
 zone:
    zone_start '{'
  | zone FILENAME TEXT ';' { this_zone->file = $3; }
+ | zone SEMANTIC_CHECKS BOOL ';' { this_zone->enable_checks = $3; }
  ;
 
 zones:
    ZONES '{'
  | zones zone '}'
+ | zones SEMANTIC_CHECKS BOOL ';' { new_config->zone_checks = $3; }
  ;
 
 log_prios_start: {
diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c
index 11d9b0d0757dbf10703b4eb5f250a3093c23f3f4..f257dd0d8ce73b2a768ffa81b3a59fd75a8c8682 100644
--- a/src/knot/conf/conf.c
+++ b/src/knot/conf/conf.c
@@ -168,6 +168,7 @@ static void zone_free(conf_zone_t *zone)
 	free(zone->name);
 	free(zone->file);
 	free(zone->db);
+	free(zone);
 }
 
 /*!
@@ -215,6 +216,11 @@ static int conf_process(conf_t *conf)
 	WALK_LIST (n, conf->zones) {
 		conf_zone_t *zone = (conf_zone_t*)n;
 
+		// Default policy for semantic checks
+		if (zone->enable_checks < 0) {
+			zone->enable_checks = conf->zone_checks;
+		}
+
 		// Normalize zone filename
 		zone->file = strcpath(zone->file);
 
@@ -391,6 +397,9 @@ conf_t *conf_new(const char* path)
 	init_list(&c->zones);
 	init_list(&c->hooks);
 
+	// Defaults
+	c->zone_checks = 0;
+
 	return c;
 }
 
@@ -573,7 +582,7 @@ int conf_open(const char* path)
 
 	/* Parse config. */
 	int ret = conf_fparser(nconf);
-	if (ret != 0) {
+	if (ret != KNOT_EOK) {
 		conf_free(nconf);
 		return ret;
 	}
@@ -583,8 +592,8 @@ int conf_open(const char* path)
 
 	/* Copy hooks. */
 	if (oldconf) {
-		node *n = 0;
-		WALK_LIST (n, oldconf->hooks) {
+		node *n = 0, *nxt = 0;
+		WALK_LIST_DELSAFE (n, nxt, oldconf->hooks) {
 			conf_hook_t *hook = (conf_hook_t*)n;
 			conf_add_hook(nconf, hook->sections,
 			              hook->update, hook->data);
diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h
index 558e5d08073ff617c3cdaa7c16ab24824874216d..732d63cc41688e8b08ea37052ec09e8e284aeb3e 100644
--- a/src/knot/conf/conf.h
+++ b/src/knot/conf/conf.h
@@ -81,6 +81,7 @@ typedef struct {
 	enum dnslib_rr_class cls;    /*!< Zone class (IN or CH). */
 	char *file;                  /*!< Path to a zone file. */
 	char *db;                    /*!< Path to a database file. */
+	int  enable_checks;          /*!< Semantic checks for parser.*/
 } conf_zone_t;
 
 /*!
@@ -146,6 +147,7 @@ typedef struct conf_t {
 	 */
 	list zones;       /*!< List of zones. */
 	int zones_count;  /*!< Count of zones. */
+	int zone_checks;  /*!< Semantic checks for parser.*/
 
 	/*
 	 * Implementation specifics
diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c
index e58ffa1194c1965b4975dacc2668be851b0f546b..016db504606801ca186ec81848a47acf5e334775 100644
--- a/src/knot/ctl/knotc_main.c
+++ b/src/knot/ctl/knotc_main.c
@@ -249,9 +249,11 @@ int execute(const char *action, char **argv, int argc, pid_t pid, int verbose,
 
 			// Prepare command
 			char* cmd = 0;
-			const char *cmd_str = "%s -o %s %s%s %s";
+			const char *cmd_str = "%s %s%s-o %s %s %s";
 			rc = asprintf(&cmd, cmd_str, ZONEPARSER_EXEC,
-			              zone->db, verbose ? "-v " : "",
+				      zone->enable_checks ? "-s " : "",
+				      verbose ? "-v " : "",
+				      zone->db,
 			              zone->name, zone->file);
 
 			// Execute command
diff --git a/src/zcompile/tests/zcompile_tests.c b/src/zcompile/tests/zcompile_tests.c
index e42ca191b775680a0731eab2bc4a02017d5b5390..20be8c30b483c01188aa56474c56af6fe4803b14 100644
--- a/src/zcompile/tests/zcompile_tests.c
+++ b/src/zcompile/tests/zcompile_tests.c
@@ -331,7 +331,7 @@ static int test_zoneparser_zone_read(const char *origin, const char *filename,
 #ifdef TEST_WITH_LDNS
 	/* Calls zcompile. */
 	parser = zparser_create();
-	int ret = zone_read(origin, filename, outfile);
+	int ret = zone_read(origin, filename, outfile, 0);
 	if (ret != 0) {
 		diag("Could not load zone from file: %s", filename);
 		return 0;
diff --git a/src/zcompile/zcompile.c b/src/zcompile/zcompile.c
index 63ba11374329180f6b825de5e5984486e27c0895..18b26c459fc9d17177ca1b83f5a6e89cf169856a 100644
--- a/src/zcompile/zcompile.c
+++ b/src/zcompile/zcompile.c
@@ -1790,7 +1790,8 @@ static uint find_rrsets_orphans(dnslib_zone_t *zone, rrset_list_t
  * Reads the specified zone into the memory
  *
  */
-int zone_read(const char *name, const char *zonefile, const char *outfile)
+int zone_read(const char *name, const char *zonefile, const char *outfile,
+              int semantic_checks)
 {
 	if (!outfile) {
 		fprintf(stderr, "Missing output file for '%s'\n",
@@ -1843,7 +1844,8 @@ int zone_read(const char *name, const char *zonefile, const char *outfile)
 
 	debug_zp("rdata adjusted\n");
 
-	dnslib_zdump_binary(parser->current_zone, outfile, 1, zonefile);
+	dnslib_zdump_binary(parser->current_zone, outfile, semantic_checks,
+	                    zonefile);
 
 	/* This is *almost* unnecessary */
 	dnslib_zone_deep_free(&(parser->current_zone), 1);
diff --git a/src/zcompile/zcompile.h b/src/zcompile/zcompile.h
index e6932cd987605b2c324a0681466149d02506abca..1bb374716912b55f70f67a7ede3776385287c4b6 100644
--- a/src/zcompile/zcompile.h
+++ b/src/zcompile/zcompile.h
@@ -398,11 +398,13 @@ uint16_t *alloc_rdata_init(const void *data, size_t size);
  * \param name Origin domain name string.
  * \param zonefile File containing the zone.
  * \param outfile File to save dump of the zone to.
+ * \param semantic_checks Enables or disables sematic checks.
  *
  * \retval 0 on success.
  * \retval -1 on error.
  */
-int zone_read(const char *name, const char *zonefile, const char *outfile);
+int zone_read(const char *name, const char *zonefile, const char *outfile,
+              int semantic_checks);
 
 /*!
  * \brief Creates zparser instance.
diff --git a/src/zcompile/zcompile_main.c b/src/zcompile/zcompile_main.c
index c64f70ef92547667f337c728f3af480144991105..d1e69b1e58fe382f3ef16058cb1fc3f59b9b7534 100644
--- a/src/zcompile/zcompile_main.c
+++ b/src/zcompile/zcompile_main.c
@@ -24,10 +24,11 @@ int main(int argc, char **argv)
 	// Parse command line arguments
 	int c = 0;
 	int verbose = 0;
+	int semantic_checks = 0;
 	const char* origin = 0;
 	const char* zonefile = 0;
 	const char* outfile = 0;
-	while ((c = getopt (argc, argv, "o:vVh")) != -1) {
+	while ((c = getopt (argc, argv, "o:vVsh")) != -1) {
 		switch (c)
 		{
 		case 'o':
@@ -42,6 +43,9 @@ int main(int argc, char **argv)
 			       PROJECT_VER >> 8 & 0x000000ff,
 			       PROJECT_VER >> 0 & 0x000000ff);
 			return 1;
+		case 's':
+			semantic_checks = 1;
+			break;
 		case 'h':
 		case '?':
 		default:
@@ -78,7 +82,7 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
-	int errors = zone_read(origin, zonefile, outfile);
+	int errors = zone_read(origin, zonefile, outfile, semantic_checks);
 
 	printf("Finished.\n");
 	//log_close();