diff --git a/samples/knot.full.conf b/samples/knot.full.conf
index bb3213e44109771515256d88d99a1b80983c401a..1b67376e7ee310e545133c98817b07f581defc66 100644
--- a/samples/knot.full.conf
+++ b/samples/knot.full.conf
@@ -23,6 +23,11 @@ system {
   # Working directory of the server
   # Used to store compiled zones and PID file
   storage "/tmp/knot-sample";
+
+  # Number of workers per interface
+  # This option is used to force number of threads used per interface
+  # Default: unset (auto-estimates optimal value from the number of online CPUs)
+  workers 1;
 }
 
 # Section 'keys' contains list of TSIG keys
diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l
index f5d38d13d9639e44918e12c4b85c2e93641d596b..97ac8f811126367756fbd55df9f20f537acc2692 100644
--- a/src/knot/conf/cf-lex.l
+++ b/src/knot/conf/cf-lex.l
@@ -72,6 +72,7 @@ xfr-in          { lval.t = yytext; return XFR_IN; }
 xfr-out         { lval.t = yytext; return XFR_OUT; }
 notify-in       { lval.t = yytext; return NOTIFY_IN; }
 notify-out      { lval.t = yytext; return NOTIFY_OUT; }
+workers         { lval.t = yytext; return WORKERS; }
 
 interfaces      { lval.t = yytext; return INTERFACES; }
 address         { lval.t = yytext; return ADDRESS; }
diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y
index 672acb9205c6bc4e88a477098b1b7b29da106a8a..d793865c841d252a3b39408380c7bd8111648ac6 100644
--- a/src/knot/conf/cf-parse.y
+++ b/src/knot/conf/cf-parse.y
@@ -155,6 +155,7 @@ static int conf_key_add(void *scanner, knot_key_t **key, char *item)
 
 %token <tok> SYSTEM IDENTITY VERSION STORAGE KEY KEYS
 %token <tok> TSIG_ALGO_NAME
+%token <tok> WORKERS
 
 %token <tok> REMOTES
 
@@ -240,9 +241,9 @@ interface:
        this_iface->address = $3.t;
        this_iface->family = AF_INET6;
        if (this_iface->port != CONFIG_DEFAULT_PORT) {
-	 cf_error(scanner, "only one port definition is allowed in interface section\n");
+          cf_error(scanner, "only one port definition is allowed in interface section\n");
        } else {
-	 this_iface->port = $5.i;
+          this_iface->port = $5.i;
        }
      }
    }
@@ -269,6 +270,13 @@ system:
 		     "and has no effect.\n");
      free($4.t);
  }
+ | system WORKERS NUM ';' { 
+     if ($3.i <= 0) { 
+        cf_error(scanner, "worker count must be greater than 0\n");
+     } else {
+        new_config->workers = $3.i;
+     }
+ }
  ;
 
 keys:
diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h
index ad61350e57b7289b05ce787c6caf27eb06ee4357..687dcc2d7583d8157b18fae94fbbf274856aa467 100644
--- a/src/knot/conf/conf.h
+++ b/src/knot/conf/conf.h
@@ -139,6 +139,7 @@ typedef struct conf_t {
 	char *version;  /*!< Version for CH TXT version.{bind|server} */
 	char *storage;  /*!< Persistent storage path for databases and such. */
 	char *pidfile;  /*!< PID file path. */
+	int   workers;  /*!< Number of workers per interface. */
 
 	/*
 	 * Log
diff --git a/src/knot/server/server.c b/src/knot/server/server.c
index 39aef26f1d4668402aca5304dc7fded8bcebca9f..8a27319b3e184fbc8cf18a72ba95962aaccf06b8 100644
--- a/src/knot/server/server.c
+++ b/src/knot/server/server.c
@@ -305,16 +305,25 @@ static int server_bind_handlers(server_t *server)
 	if (!server || !server->ifaces) {
 		return KNOTD_EINVAL;
 	}
+	
+	/* Lock config. */
+	conf_read_lock();
 
 	/* Estimate number of threads/manager. */
-	int thr_count = dt_optimal_size();
-	int tcp_unit_size = (thr_count >> 1);
-	if (tcp_unit_size < 3) {
-		tcp_unit_size = 3;
+	int thr_count = 0;
+	int tcp_unit_size = 0;
+	if (conf()->workers < 1) {
+		thr_count = dt_optimal_size();
+		tcp_unit_size = (thr_count * 2) + 1; /* Will be always odd. */
+	} else {
+		thr_count = conf()->workers;
+		tcp_unit_size = thr_count + 1; /* Force configured value. */
 	}
-
-	/* Lock config. */
-	conf_read_lock();
+	
+	dbg_server("server: configured %d worker%s per UDP iface\n",
+	           thr_count, thr_count > 1 ? "s" : "");
+	dbg_server("server: configured %d worker%s per TCP iface\n",
+	           tcp_unit_size - 1, (tcp_unit_size - 1) > 1 ? "s" : "");
 
 	/* Create socket handlers. */
 	node *n = 0;
@@ -333,7 +342,7 @@ static int server_bind_handlers(server_t *server)
 
 			/* Save pointer. */
 			rcu_set_pointer(&iface->handler[UDP_ID], h);
-			dbg_server("Creating UDP socket handlers for '%s:%d'\n",
+			dbg_server("server: creating UDP socket handlers for '%s:%d'\n",
 			             iface->addr, iface->port);
 
 		}
@@ -348,7 +357,7 @@ static int server_bind_handlers(server_t *server)
 
 			/* Save pointer. */
 			rcu_set_pointer(&iface->handler[TCP_ID], h);
-			dbg_server("Creating TCP socket handlers for '%s:%d'\n",
+			dbg_server("server: creating TCP socket handlers for '%s:%d'\n",
 			             iface->addr, iface->port);
 		}
 
@@ -375,21 +384,21 @@ server_t *server_create()
 	init_list(server->ifaces);
 
 	// Create event scheduler
-	dbg_server("Creating event scheduler...\n");
+	dbg_server("server: creating event scheduler\n");
 	server->sched = evsched_new();
 	dt_unit_t *unit = dt_create_coherent(1, evsched_run, 0);
 	iohandler_t *h = server_create_handler(server, -1, unit);
 	h->data = server->sched;
 
 	// Create name server
-	dbg_server("Creating Name Server structure...\n");
+	dbg_server("server: creating Name Server structure\n");
 	server->nameserver = knot_ns_create();
 	if (server->nameserver == NULL) {
 		free(server);
 		return NULL;
 	}
 	knot_ns_set_data(server->nameserver, server);
-	dbg_server("Initializing OpenSSL...\n");
+	dbg_server("server: initializing OpenSSL\n");
 	OpenSSL_add_all_digests();
 
 	// Create XFR handler
@@ -400,7 +409,7 @@ server_t *server_create()
 		return NULL;
 	}
 
-	dbg_server("Done.\n");
+	dbg_server("server: created server instance\n");
 	return server;
 }
 
@@ -509,7 +518,7 @@ int server_start(server_t *server)
 		return KNOTD_EINVAL;
 	}
 
-	dbg_server("Starting handlers...\n");
+	dbg_server("server: starting server instance\n");
 
 	/* Start XFR handler. */
 	xfr_start(server->xfr_h);
@@ -538,7 +547,7 @@ int server_start(server_t *server)
 	/* Unlock configuration. */
 	conf_read_unlock();
 
-	dbg_server("Done.\n");
+	dbg_server("server: server started\n");
 
 	return ret;
 }
@@ -578,6 +587,8 @@ int server_wait(server_t *server)
 
 void server_stop(server_t *server)
 {
+	dbg_server("server: stopping server\n");
+	
 	/* Wait for XFR master. */
 	xfr_stop(server->xfr_h);
 
@@ -620,6 +631,8 @@ void server_destroy(server_t **server)
 		return;
 	}
 	
+	dbg_server("server: destroying server instance\n");
+	
 	// Free XFR master
 	xfr_free((*server)->xfr_h);
 
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index ab93bdf4a18d44bd9c6ce5bb1e23ee1e8a2e0c53..b96d32ea06ccbc160e0d49c1fbbf7c50ba46170f 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -672,7 +672,7 @@ static int zones_load_zone(knot_zonedb_t *zonedb, const char *zone_name,
 
 	// Check path
 	if (filename) {
-		dbg_server("Parsing zone database '%s'\n", filename);
+		dbg_zones("zones: parsing zone database '%s'\n", filename);
 		zloader_t *zl = 0;
 		int ret = knot_zload_open(&zl, filename);
 		switch(ret) {