diff --git a/inc/common/macro.h b/inc/common/macro.h
index fe3ad89047837b868929bff89a6791e462b7415c..99e756c10b7dc822b57e7852296c5d1944394d7a 100644
--- a/inc/common/macro.h
+++ b/inc/common/macro.h
@@ -55,7 +55,7 @@ enum log_level {
 
 #define LOG(format, level, section, ...)                                                \
     {                                                                                   \
-        if (level >= log_level)                                                         \
+        if (level <= log_level)                                                         \
             fprintf(stderr, " %c %s%s: " format "\n",                                   \
                 level == ERROR ? '!' : level == WARN ? '*' : level == INFO ? '.' : ' ', \
                 sizeof(section) > sizeof("") ? ("[" section "] ") : "",                 \
diff --git a/src/common.c b/src/common.c
index 06d37addec3f2235d0aa26fd929305d01cec64fe..cc7dd77b7bc4b3fae7c0afd2112db61c8c9de9c0 100644
--- a/src/common.c
+++ b/src/common.c
@@ -8,7 +8,7 @@
 #include <stdarg.h>
 #include <sys/stat.h>
 
-int log_level = INFO;
+int log_level = 0; /* None by default */
 
 void
 __not_implemented(const char *func, char *file, int line)
diff --git a/src/config.c b/src/config.c
index f2ccb89a8400e9f78d1739243496f44c3b67f75b..647bb9e0e3b9b70771164a943c1a567a424bf66c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -6,6 +6,7 @@
 #include <lektor/net.h>
 #include <lektor/reg.h>
 
+#include <strings.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
@@ -46,6 +47,34 @@ handler(volatile sqlite3 *user, const char *section, const char *name,
     return 0;
 }
 
+static inline void
+__set_log_level(const char *name, const char *level)
+{
+    if (!STR_MATCH(name, "log")) {
+        LOG_WARN("CONFIG", "Invalid option '%s[:=]%s' with no section",
+                 name, level);
+        return;
+    }
+
+    if (!level[0]) {
+        LOG_WARN("CONFIG", "%s", "Invalid empty 'log' option");
+        return;
+    }
+
+    if (STR_MATCH(level, "error"))
+        log_level = ERROR;
+    else if (STR_MATCH(level, "warn") || STR_MATCH(level, "warning"))
+        log_level = WARN;
+    else if (STR_MATCH(level, "info"))
+        log_level = INFO;
+    else if (STR_MATCH(level, "debug"))
+        log_level = DEBUG;
+    else
+        log_level = strtol(level, NULL, 0);
+
+    LOG_INFO("CONFIG", "Log level set to %d", log_level);
+}
+
 static inline int
 ini_parse(const char *path, volatile sqlite3 *db)
 {
@@ -58,6 +87,9 @@ ini_parse(const char *path, volatile sqlite3 *db)
         return 1;
     }
 
+    memset(section, 0, INI_MAX_SECTION_LEN);
+    memset(line, 0, INI_MAX_LINE_LEN);
+
     /* Parse the file */
     while (NULL != fgets(line, INI_MAX_LINE_LEN, file)) {
         ++linenum;
@@ -102,13 +134,18 @@ ini_parse(const char *path, volatile sqlite3 *db)
                 value = skip(value);
                 strip(value);
 
-                /* Handle the SECTION, NAME[:=]VALUE */
-                if (handler(db, section, name, value)) {
-                    error = 1;
-                    LOG_ERROR("PARSER", "Failed to '[handle] %s, "
-                              "%s{:,=}%s' at line '%d'",
-                              section, name, value, linenum);
-                }
+                /* Handle the SECTION, NAME[:=]VALUE
+                   The only option that has no SECTION is the log level:
+                   log[:=]ERROR|WARN|INFO|DEBUG|\d+ */
+                if (section[0]) {
+                    if (handler(db, section, name, value)) {
+                        error = 1;
+                        LOG_ERROR("PARSER", "Failed to '[handle] %s, "
+                                  "%s{:,=}%s' at line '%d'",
+                                  section, name, value, linenum);
+                    }
+                } else
+                    __set_log_level(name, value);
             }
 
             else {
diff --git a/src/main/lkt.c b/src/main/lkt.c
index 58471c17cb42cb2d0e341c062e15e5ac3ad197f4..cc044f05a918122590e5dcac07e4e10e3c97e282 100644
--- a/src/main/lkt.c
+++ b/src/main/lkt.c
@@ -941,6 +941,7 @@ parse_args(args_t *args, int argc, const char **argv)
 int
 main(int argc, const char **argv)
 {
+    log_level = ERROR;
     executable_name = "lkt";
     assert(NULL != setlocale(LC_ALL, "en_US.UTF-8"));   /* BECAUSE! */
     assert(!signal(SIGPIPE, sigpipe__));
diff --git a/src/main/server.c b/src/main/server.c
index 726c83ab1cb7afdcacc5ba861286046ed5bcdc13..5f760ed573a062778686b636141b51fc6845cd22 100644
--- a/src/main/server.c
+++ b/src/main/server.c
@@ -66,10 +66,6 @@ main(int argc, char *argv[])
     }
 
 normal_launch:
-    LOG_INFO("GENERAL", "Lektor launched by user %s (shell: %s, home: %s)",
-             pw->pw_name, pw->pw_shell, pw->pw_dir);
-    if (env_get(LKT_ENV_RESTART))
-        LOG_INFO("GENERAL", "%s", "Lektord has been restarted");
     reg_set(server_reg);
     mthread_init();
     pthread_create(&th, NULL, mthread_main, NULL);
@@ -136,6 +132,10 @@ normal_launch:
         lkt_queue_send(&srv.queue, lkt_event_play_pos, (void *) (size_t) strtol(env_current, NULL, 0));
     }
 
+    LOG_INFO("GENERAL", "Lektor was %s, user: %s, shell: %s, home: %s",
+             env_get(LKT_ENV_RESTART) ? "restarted" : "started",
+             pw->pw_name, pw->pw_shell, pw->pw_dir);
+
     lkt_listen(&srv);
     return EXIT_FAILURE;
 }