diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y
index 0db4e115d1d034b9f36d13cfbe951057f70b0151..56fb2b3ac6d590d1dab3a79126134a8d03153a87 100644
--- a/src/knot/conf/cf-parse.y
+++ b/src/knot/conf/cf-parse.y
@@ -43,6 +43,7 @@
 
 extern int cf_lex (YYSTYPE *lvalp, void *scanner);
 extern void cf_error(void *scanner, const char *format, ...);
+extern void cf_warning(void *scanner, const char *format, ...);
 extern conf_t *new_config;
 static conf_iface_t *this_iface = 0;
 static conf_iface_t *this_remote = 0;
@@ -53,6 +54,8 @@ static conf_log_t *this_log = 0;
 static conf_log_map_t *this_logmap = 0;
 //#define YYERROR_VERBOSE 1
 
+static char *cache_hostname = NULL;
+
 #define SET_NUM(out, in, min, max, name)				\
 {									\
 	if (in < min || in > max) {					\
@@ -67,6 +70,11 @@ static conf_log_map_t *this_logmap = 0;
 #define SET_INT(out, in, name) SET_NUM(out, in, 0, INT_MAX, name);
 #define SET_SIZE(out, in, name) SET_NUM(out, in, 0, SIZE_MAX, name);
 
+static void conf_start(void *scanner)
+{
+	cache_hostname = NULL;
+}
+
 static void conf_init_iface(void *scanner, char* ifname)
 {
 	this_iface = malloc(sizeof(conf_iface_t));
@@ -419,18 +427,35 @@ static void opt_replace(char **opt, char *new_opt, bool val)
 	}
 }
 
+static char *get_hostname(void *scanner)
+{
+	if (cache_hostname) {
+		return strdup(cache_hostname);
+	}
+
+	char *fqdn = sockaddr_hostname();
+	if (!fqdn) {
+		cf_warning(scanner, "cannot retrieve host FQDN");
+		return NULL;
+	}
+
+	cache_hostname = fqdn;
+
+	return fqdn;
+}
+
 /*! \brief Generate automatic defaults for server identity, version and NSID. */
-static void ident_auto(int tok, conf_t *conf, bool val)
+static void ident_auto(void *scanner, int tok, conf_t *conf, bool val)
 {
 	switch(tok) {
 	case SVERSION:
 		opt_replace(&conf->version, strdup("Knot DNS " PACKAGE_VERSION), val);
 		break;
 	case IDENTITY:
-		opt_replace(&conf->identity, sockaddr_hostname(), val);
+		opt_replace(&conf->identity, get_hostname(scanner), val);
 		break;
 	case NSID:
-		opt_replace(&conf->nsid, sockaddr_hostname(), val);
+		opt_replace(&conf->nsid, get_hostname(scanner), val);
 		if (conf->nsid) {
 			conf->nsid_len = strlen(conf->nsid);
 		}
@@ -519,7 +544,7 @@ static void ident_auto(int tok, conf_t *conf, bool val)
 
 %%
 
-config: conf_entries END { return 0; } ;
+config: { conf_start(scanner); } conf_entries END { return 0; } ;
 
 conf_entries:
  /* EMPTY */
@@ -569,31 +594,30 @@ interfaces:
 system:
    SYSTEM '{'
  | system SVERSION TEXT ';' { new_config->version = $3.t; }
- | system SVERSION BOOL ';' { ident_auto(SVERSION, new_config, $3.i); }
+ | system SVERSION BOOL ';' { ident_auto(scanner, SVERSION, new_config, $3.i); }
  | system IDENTITY TEXT ';' { new_config->identity = $3.t; }
- | system IDENTITY BOOL ';' { ident_auto(IDENTITY, new_config, $3.i); }
+ | system IDENTITY BOOL ';' { ident_auto(scanner, IDENTITY, new_config, $3.i); }
  | system HOSTNAME TEXT ';' {
-     fprintf(stderr, "warning: Config option 'system.hostname' is deprecated. "
-                     "Use 'system.identity' instead.\n");
+     cf_warning(scanner, "option 'system.hostname' is deprecated, "
+                         "use 'system.identity' instead");
      free($3.t);
  }
  | system NSID HEXSTR ';' { new_config->nsid = $3.t; new_config->nsid_len = $3.l; }
  | system NSID TEXT ';' { new_config->nsid = $3.t; new_config->nsid_len = strlen(new_config->nsid); }
- | system NSID BOOL ';' { ident_auto(NSID, new_config, $3.i); }
+ | system NSID BOOL ';' { ident_auto(scanner, NSID, new_config, $3.i); }
  | system MAX_UDP_PAYLOAD NUM ';' {
      SET_NUM(new_config->max_udp_payload, $3.i, KNOT_EDNS_MIN_UDP_PAYLOAD,
              KNOT_EDNS_MAX_UDP_PAYLOAD, "max-udp-payload");
  }
  | system STORAGE TEXT ';' {
-     fprintf(stderr, "warning: Config option 'system.storage' was relocated. "
-                     "Use 'zones.storage' instead.\n");
+     cf_warning(scanner, "option 'system.storage' was relocated, "
+                         "use 'zones.storage' instead");
      new_config->storage = $3.t;
  }
  | system RUNDIR TEXT ';' { new_config->rundir = $3.t; }
  | system PIDFILE TEXT ';' { new_config->pidfile = $3.t; }
  | system KEY TSIG_ALGO_NAME TEXT ';' {
-     fprintf(stderr, "warning: Config option 'system.key' is deprecated "
-                     "and has no effect.\n");
+     cf_warning(scanner, "option 'system.key' is deprecated and it has no effect");
      free($4.t);
  }
  | system WORKERS NUM ';' {
@@ -983,8 +1007,8 @@ log_prios_start: {
 log_prios:
    log_prios_start
  | log_prios LOG_LEVEL ',' { this_logmap->prios |= $2.i;
-	fprintf(stderr, "Warning: more log severities per statement is deprecated. "
-	                "Using the least serious one.\n");
+	cf_warning(scanner, "multiple log severities are deprecated, "
+	                    "using the least serious one");
  }
  | log_prios LOG_LEVEL ';' { this_logmap->prios |= $2.i; }
  ;
diff --git a/src/knot/conf/conf.c b/src/knot/conf/conf.c
index 0e7575b443e9cff6647636688ea034205dc45809..598a5031862756c68d8b65f51c33f35c3e40e642 100644
--- a/src/knot/conf/conf.c
+++ b/src/knot/conf/conf.c
@@ -59,7 +59,7 @@ conf_t *new_config = NULL; /*!< \brief Currently parsed config. */
 static volatile int _parser_res = 0; /*!< \brief Parser result. */
 static pthread_mutex_t _parser_lock = PTHREAD_MUTEX_INITIALIZER;
 
-static void cf_print_error(void *scanner, const char *msg)
+static void cf_print_error(void *scanner, int priority, const char *msg)
 {
 	conf_extra_t *extra = NULL;
 	int lineno = -1;
@@ -84,10 +84,8 @@ static void cf_print_error(void *scanner, const char *msg)
 		filename = new_config->filename;
 	}
 
-	log_error("config error, file '%s', line %d, token '%s' (%s)",
-		  filename, lineno, text, msg);
-
-	_parser_res = KNOT_EPARSEFAIL;
+	log_msg(priority, "config, file '%s', line %d, token '%s', %s",
+	        filename, lineno, text, msg);
 }
 
 /*! \brief Config error report. */
@@ -100,7 +98,21 @@ void cf_error(void *scanner, const char *format, ...)
 	vsnprintf(buffer, sizeof(buffer), format, ap);
 	va_end(ap);
 
-	cf_print_error(scanner, buffer);
+	cf_print_error(scanner, LOG_ERR, buffer);
+	_parser_res = KNOT_EPARSEFAIL;
+}
+
+/*! \brief Config warning report. */
+void cf_warning(void *scanner, const char *format, ...)
+{
+	char buffer[ERROR_BUFFER_SIZE];
+	va_list ap;
+
+	va_start(ap, format);
+	vsnprintf(buffer, sizeof(buffer), format, ap);
+	va_end(ap);
+
+	cf_print_error(scanner, LOG_WARNING, buffer);
 }
 
 /*!