diff --git a/UPGRADE.txt b/UPGRADE.txt
index c5d60af8ac5e8bb85d8f40e2bc632fa917ef5673..e331e92c72d856beadac1bf72d4b4fbb59407ef0 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -20,6 +20,32 @@
 ===
 ===========================================================
 
+From 11.7 to 11.8:
+* The per console verbose level feature as previously implemented caused a
+  large performance penalty.  The fix required some minor incompatibilities
+  if the new rasterisk is used to connect to an earlier version.  If the new
+  rasterisk connects to an older Asterisk version then the root console verbose
+  level is always affected by the "core set verbose" command of the remote
+  console even though it may appear to only affect the current console.  If
+  an older version of rasterisk connects to the new version then the
+  "core set verbose" command will have no effect.
+
+CLI commands:
+ - "core show settings" now lists the current console verbosity in addition
+   to the root console verbosity.
+
+ - "core set verbose" has not been able to support the by module verbose
+   logging levels since verbose logging levels were made per console.  That
+   syntax is now removed and a silence option added in its place.
+
+Configuration Files:
+ - The 'verbose' setting in logger.conf still takes an optional argument,
+   specifying the verbosity level for each logging destination.  However,
+   the default is now to once again follow the current root console level.
+   As a result, using the AMI Command action with "core set verbose" could
+   again set the root console verbose level and affect the verbose level
+   logged.
+
 From 11.6 to 11.7:
 ConfBridge
  - ConfBridge now has the ability to set the language of announcements to the
diff --git a/apps/app_dumpchan.c b/apps/app_dumpchan.c
index 5370a402f7b84774956a32e6800fb6445a7131f1..c2cff6114c0dbf62d2fddb2e9a855ac5339e7b8c 100644
--- a/apps/app_dumpchan.c
+++ b/apps/app_dumpchan.c
@@ -182,15 +182,17 @@ static int dumpchan_exec(struct ast_channel *chan, const char *data)
 	if (!ast_strlen_zero(data))
 		level = atoi(data);
 
-	serialize_showchan(chan, info, sizeof(info));
-	pbx_builtin_serialize_variables(chan, &vars);
-	ast_verb(level, "\n"
-		 "Dumping Info For Channel: %s:\n"
-		 "%s\n"
-		 "Info:\n"
-		 "%s\n"
-		 "Variables:\n"
-		 "%s%s\n", ast_channel_name(chan), line, info, ast_str_buffer(vars), line);
+	if (VERBOSITY_ATLEAST(level)) {
+		serialize_showchan(chan, info, sizeof(info));
+		pbx_builtin_serialize_variables(chan, &vars);
+		ast_verb(level, "\n"
+			"Dumping Info For Channel: %s:\n"
+			"%s\n"
+			"Info:\n"
+			"%s\n"
+			"Variables:\n"
+			"%s%s\n", ast_channel_name(chan), line, info, ast_str_buffer(vars), line);
+	}
 
 	return 0;
 }
diff --git a/apps/app_verbose.c b/apps/app_verbose.c
index 394c489912c2279e2fe5da50b24cce05c3231ef7..8d285b02f707285efa8bf247832518261352b8bc 100644
--- a/apps/app_verbose.c
+++ b/apps/app_verbose.c
@@ -96,9 +96,11 @@ static int verbose_exec(struct ast_channel *chan, const char *data)
 		args.level = "0";
 	}
 
-	if (sscanf(args.level, "%30d", &vsize) != 1) {
+	if (sscanf(args.level, "%30u", &vsize) != 1) {
 		vsize = 0;
 		ast_log(LOG_WARNING, "'%s' is not a verboser number\n", args.level);
+	} else if (4 < vsize) {
+		vsize = 4;
 	}
 
 	ast_verb(vsize, "%s\n", args.msg);
diff --git a/configs/logger.conf.sample b/configs/logger.conf.sample
index 1fdac703015cf35194807d4775af89380cbc26a6..07d8f1b83e78d4943795d09f8cf025f09e857dd3 100644
--- a/configs/logger.conf.sample
+++ b/configs/logger.conf.sample
@@ -83,24 +83,25 @@
 ;    fax
 ;    security
 ;
-; Special filename "console" represents the system console
+; Special filename "console" represents the root console
 ;
 ; Filenames can either be relative to the standard Asterisk log directory
 ; (see 'astlogdir' in asterisk.conf), or absolute paths that begin with
 ; '/'.
 ;
+; Verbose takes an optional argument, in the form of an integer level.
+; Verbose messages with higher levels will not be logged to the file.  If
+; the verbose level is not specified, it will log verbose messages following
+; the current level of the root console.
+;
 ; Special level name "*" means all levels, even dynamic levels registered
 ; by modules after the logger has been initialized (this means that loading
 ; and unloading modules that create/remove dynamic logger levels will result
 ; in these levels being included on filenames that have a level name of "*",
-; without any need to perform a 'logger reload' or similar operation). Note
-; that there is no value in specifying both "*" and specific level names for
-; a filename; the "*" level means all levels, and the remaining level names
-; will be ignored.
-;
-; Verbose takes an additional argument, in the form of an integer level.
-; Messages with higher levels will be ignored.  If verbose is specified at
-; all, it will default to 3.
+; without any need to perform a 'logger reload' or similar operation).
+; Note that there is no value in specifying both "*" and specific level names
+; for a filename; the "*" level means all levels.  The only exception is if
+; you need to specify a specific verbose level. e.g, "verbose(3),*".
 ;
 ; We highly recommend that you DO NOT turn on debug mode if you are simply
 ; running a production system.  Debug mode turns on a LOT of extra messages,
diff --git a/funcs/func_timeout.c b/funcs/func_timeout.c
index 3c2810fd5e38b795080ff5002004b58dc37f5b37..ea4e64bcf4d433f1202f805becb9d7dc4f9ef992 100644
--- a/funcs/func_timeout.c
+++ b/funcs/func_timeout.c
@@ -156,13 +156,15 @@ static int timeout_write(struct ast_channel *chan, const char *cmd, char *data,
 	case 'a':
 	case 'A':
 		ast_channel_setwhentohangup_tv(chan, when);
-		if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
-			when = ast_tvadd(when, ast_tvnow());
-			ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S.%3q %Z",
-				ast_localtime(&when, &myt, NULL));
-			ast_verb(3, "Channel will hangup at %s.\n", timestr);
-		} else {
-			ast_verb(3, "Channel hangup cancelled.\n");
+		if (VERBOSITY_ATLEAST(3)) {
+			if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
+				when = ast_tvadd(when, ast_tvnow());
+				ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S.%3q %Z",
+					ast_localtime(&when, &myt, NULL));
+				ast_verb(3, "Channel will hangup at %s.\n", timestr);
+			} else {
+				ast_verb(3, "Channel hangup cancelled.\n");
+			}
 		}
 		break;
 
diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h
index 6c2291dc556a31d29f295aca01f152dc2ed74e53..df11e424d5ac8a8f95dc298dbffa54c76f8e1387 100644
--- a/include/asterisk/logger.h
+++ b/include/asterisk/logger.h
@@ -87,21 +87,29 @@ int logger_reload(void);
 
 void __attribute__((format(printf, 5, 6))) ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...);
 
-/*! Send a verbose message (based on verbose level)
- *	\brief This works like ast_log, but prints verbose messages to the console depending on verbosity level set.
- *	ast_verbose(VERBOSE_PREFIX_3 "Whatever %s is happening\n", "nothing");
- *	This will print the message to the console if the verbose level is set to a level >= 3
- *	Note the absence of a comma after the VERBOSE_PREFIX_3.  This is important.
- *	VERBOSE_PREFIX_1 through VERBOSE_PREFIX_4 are defined.
- *  \version 11 added level parameter
+/*!
+ * \brief Send a verbose message (based on verbose level)
+ *
+ * \details This works like ast_log, but prints verbose messages to the console depending on verbosity level set.
+ *
+ * ast_verbose(VERBOSE_PREFIX_3 "Whatever %s is happening\n", "nothing");
+ *
+ * This will print the message to the console if the verbose level is set to a level >= 3
+ *
+ * Note the absence of a comma after the VERBOSE_PREFIX_3.  This is important.
+ * VERBOSE_PREFIX_1 through VERBOSE_PREFIX_4 are defined.
+ *
+ * \version 11 added level parameter
  */
 void __attribute__((format(printf, 5, 6))) __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...);
 
-/*! Send a verbose message (based on verbose level) with deliberately specified callid
- *  \brief just like __ast_verbose, only __ast_verbose_callid allows you to specify which callid is being used
- *  for the log without needing to bind it to a thread. NULL is a valid argument for this function and will
- *  allow you to specify that a log will never display a call id even when there is a call id bound to the
- *  thread.
+/*!
+ * \brief Send a verbose message (based on verbose level) with deliberately specified callid
+ *
+ * \details just like __ast_verbose, only __ast_verbose_callid allows you to specify which callid is being used
+ * for the log without needing to bind it to a thread. NULL is a valid argument for this function and will
+ * allow you to specify that a log will never display a call id even when there is a call id bound to the
+ * thread.
  */
 void __attribute__((format(printf, 6, 7))) __ast_verbose_callid(const char *file, int line, const char *func, int level, struct ast_callid *callid, const char *fmt, ...);
 
@@ -115,6 +123,14 @@ void __attribute__((format(printf, 2, 3))) ast_child_verbose(int level, const ch
 int ast_register_verbose(void (*verboser)(const char *string)) attribute_warn_unused_result;
 int ast_unregister_verbose(void (*verboser)(const char *string)) attribute_warn_unused_result;
 
+/*
+ * These gymnastics are due to platforms which designate char as unsigned by
+ * default.  Level is the negative character -- offset by 1, because \0 is
+ * the string terminator.
+ */
+#define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
+#define VERBOSE_HASMAGIC(x)	(*(signed char *) (x) < 0)
+
 void ast_console_puts(const char *string);
 
 /*!
@@ -222,8 +238,9 @@ unsigned int ast_debug_get_by_module(const char *module);
  * \brief Get the verbose level for a module
  * \param module the name of module
  * \return the verbose level
+ * \version 11.0.0 deprecated
  */
-unsigned int ast_verbose_get_by_module(const char *module);
+unsigned int ast_verbose_get_by_module(const char *module) __attribute__((deprecated));
 
 /*!
  * \brief Register a new logger level
@@ -359,8 +376,62 @@ void ast_callid_strnprint(char *buffer, size_t buffer_size, struct ast_callid *c
 		ast_log(AST_LOG_DEBUG, __VA_ARGS__); \
 } while (0)
 
-#define ast_verb(level, ...) __ast_verbose(__FILE__, __LINE__, __PRETTY_FUNCTION__, level, __VA_ARGS__)
-#define ast_verb_callid(level, callid, ...) __ast_verbose_callid(__FILE__, __LINE__, __PRETTY_FUNCTION__, level, callid, __VA_ARGS__)
+extern int ast_verb_sys_level;
+
+#define VERBOSITY_ATLEAST(level) ((level) <= ast_verb_sys_level)
+
+#define ast_verb(level, ...) \
+	do { \
+		if (VERBOSITY_ATLEAST(level) ) { \
+			__ast_verbose(__FILE__, __LINE__, __PRETTY_FUNCTION__, level, __VA_ARGS__); \
+		} \
+	} while (0)
+
+#define ast_verb_callid(level, callid, ...) \
+	do { \
+		if (VERBOSITY_ATLEAST(level) ) { \
+			__ast_verbose_callid(__FILE__, __LINE__, __PRETTY_FUNCTION__, level, callid, __VA_ARGS__); \
+		} \
+	} while (0)
+
+/*!
+ * \brief Re-evaluate the system max verbosity level (ast_verb_sys_level).
+ *
+ * \return Nothing
+ */
+void ast_verb_update(void);
+
+/*!
+ * \brief Register this thread's console verbosity level pointer.
+ *
+ * \param level Where the verbose level value is.
+ *
+ * \return Nothing
+ */
+void ast_verb_console_register(int *level);
+
+/*!
+ * \brief Unregister this thread's console verbosity level.
+ *
+ * \return Nothing
+ */
+void ast_verb_console_unregister(void);
+
+/*!
+ * \brief Get this thread's console verbosity level.
+ *
+ * \retval verbosity level of the console.
+ */
+int ast_verb_console_get(void);
+
+/*!
+ * \brief Set this thread's console verbosity level.
+ *
+ * \param verb_level New level to set.
+ *
+ * \return Nothing
+ */
+void ast_verb_console_set(int verb_level);
 
 #ifndef _LOGGER_BACKTRACE_H
 #define _LOGGER_BACKTRACE_H
diff --git a/main/asterisk.c b/main/asterisk.c
index b8bd4be6aa2e5772ab066706ec5565383ebe5612..5843c075ad2258043cf8f699b166f5844254d916 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -191,6 +191,9 @@ int daemon(int, int);  /* defined in libresolv of all places */
 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
 struct ast_flags ast_compat = { 0 };
 
+/*! Maximum active system verbosity level. */
+int ast_verb_sys_level;
+
 int option_verbose;				/*!< Verbosity level */
 int option_debug;				/*!< Debug level */
 double option_maxload;				/*!< Max load avg on system */
@@ -219,6 +222,8 @@ struct console {
 	int uid;			/*!< Remote user ID. */
 	int gid;			/*!< Remote group ID. */
 	int levels[NUMLOGLEVELS];	/*!< Which log levels are enabled for the console */
+	/*! Verbosity level of this console. */
+	int option_verbose;
 };
 
 struct ast_atexit {
@@ -480,7 +485,8 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
 		ast_cli(a->fd, "  Maximum open file handles:   %d\n", option_maxfiles);
 	else
 		ast_cli(a->fd, "  Maximum open file handles:   Not set\n");
-	ast_cli(a->fd, "  Verbosity:                   %d\n", option_verbose);
+	ast_cli(a->fd, "  Root console verbosity:      %d\n", option_verbose);
+	ast_cli(a->fd, "  Current console verbosity:   %d\n", ast_verb_console_get());
 	ast_cli(a->fd, "  Debug level:                 %d\n", option_debug);
 	ast_cli(a->fd, "  Maximum load average:        %lf\n", option_maxload);
 #if defined(HAVE_SYSINFO)
@@ -1182,29 +1188,33 @@ void ast_console_toggle_mute(int fd, int silent)
 }
 
 /*!
- * \brief log the string to all attached console clients
+ * \brief log the string to all attached network console clients
  */
 static void ast_network_puts_mutable(const char *string, int level)
 {
 	int x;
-	for (x = 0;x < AST_MAX_CONNECTS; x++) {
-		if (consoles[x].mute)
+
+	for (x = 0; x < AST_MAX_CONNECTS; ++x) {
+		if (consoles[x].fd < 0
+			|| consoles[x].mute
+			|| consoles[x].levels[level]) {
 			continue;
-		if (consoles[x].fd > -1) {
-			if (!consoles[x].levels[level])
-				fdprint(consoles[x].p[1], string);
 		}
+		fdprint(consoles[x].p[1], string);
 	}
 }
 
 /*!
- * \brief log the string to the console, and all attached
- * console clients
+ * \brief log the string to the root console, and all attached
+ * network console clients
  */
 void ast_console_puts_mutable(const char *string, int level)
 {
+	/* Send to the root console */
 	fputs(string, stdout);
 	fflush(stdout);
+
+	/* Send to any network console clients */
 	ast_network_puts_mutable(string, level);
 }
 
@@ -1214,26 +1224,45 @@ void ast_console_puts_mutable(const char *string, int level)
 static void ast_network_puts(const char *string)
 {
 	int x;
-	for (x = 0; x < AST_MAX_CONNECTS; x++) {
-		if (consoles[x].fd > -1)
-			fdprint(consoles[x].p[1], string);
+
+	for (x = 0; x < AST_MAX_CONNECTS; ++x) {
+		if (consoles[x].fd < 0) {
+			continue;
+		}
+		fdprint(consoles[x].p[1], string);
 	}
 }
 
 /*!
- * write the string to the console, and all attached
- * console clients
+ * write the string to the root console, and all attached
+ * network console clients
  */
 void ast_console_puts(const char *string)
 {
+	/* Send to the root console */
 	fputs(string, stdout);
 	fflush(stdout);
+
+	/* Send to any network console clients */
 	ast_network_puts(string);
 }
 
-static void network_verboser(const char *s)
+static void network_verboser(const char *string)
 {
-	ast_network_puts_mutable(s, __LOG_VERBOSE);
+	int x;
+	int verb_level;
+
+	/* Send to any network console clients if client verbocity allows. */
+	verb_level = VERBOSE_MAGIC2LEVEL(string);
+	for (x = 0; x < AST_MAX_CONNECTS; ++x) {
+		if (consoles[x].fd < 0
+			|| consoles[x].mute
+			|| consoles[x].levels[__LOG_VERBOSE]
+			|| consoles[x].option_verbose < verb_level) {
+			continue;
+		}
+		fdprint(consoles[x].p[1], string);
+	}
 }
 
 static pthread_t lthread;
@@ -1297,6 +1326,7 @@ static int read_credentials(int fd, char *buffer, size_t size, struct console *c
 	return result;
 }
 
+/* This is the thread running the remote console on the main process. */
 static void *netconsole(void *vconsole)
 {
 	struct console *con = vconsole;
@@ -1312,6 +1342,7 @@ static void *netconsole(void *vconsole)
 		ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
 	snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
 	fdprint(con->fd, outbuf);
+	ast_verb_console_register(&con->option_verbose);
 	for (;;) {
 		fds[0].fd = con->fd;
 		fds[0].events = POLLIN;
@@ -1374,6 +1405,7 @@ static void *netconsole(void *vconsole)
 				break;
 		}
 	}
+	ast_verb_console_unregister();
 	if (!ast_opt_hide_connect) {
 		ast_verb(3, "Remote UNIX connection disconnected\n");
 	}
@@ -1426,24 +1458,25 @@ static void *listener(void *unused)
 					}
 					if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
 						ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
-						consoles[x].fd = -1;
 						fdprint(s, "Server failed to create pipe\n");
 						close(s);
 						break;
 					}
 					flags = fcntl(consoles[x].p[1], F_GETFL);
 					fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
-					consoles[x].fd = s;
 					consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
 					/* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
 					   to know if the user didn't send the credentials. */
 					consoles[x].uid = -2;
 					consoles[x].gid = -2;
+					/* Server default of remote console verbosity level is OFF. */
+					consoles[x].option_verbose = 0;
+					consoles[x].fd = s;
 					if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
+						consoles[x].fd = -1;
 						ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
 						close(consoles[x].p[0]);
 						close(consoles[x].p[1]);
-						consoles[x].fd = -1;
 						fdprint(s, "Server failed to spawn thread\n");
 						close(s);
 					}
@@ -1936,12 +1969,6 @@ static int console_state_init(void *ptr)
 
 AST_THREADSTORAGE_CUSTOM(console_state, console_state_init, ast_free_ptr);
 
-/* These gymnastics are due to platforms which designate char as unsigned by
- * default. Level is the negative character -- offset by 1, because \0 is the
- * EOS delimiter. */
-#define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
-#define VERBOSE_HASMAGIC(x)	(*(signed char *) (x) < 0)
-
 static int console_print(const char *s, int local)
 {
 	struct console_state_data *state =
@@ -2036,6 +2063,7 @@ static int ast_all_zeros(char *s)
 	return 1;
 }
 
+/* This is the main console CLI command handler.  Run by the main() thread. */
 static void consolehandler(char *s)
 {
 	printf("%s", term_end());
@@ -2073,38 +2101,56 @@ static int remoteconsolehandler(char *s)
 		else
 			ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
 		ret = 1;
-	} else if (strncasecmp(s, "core set verbose ", 17) == 0) {
-		int old_verbose = option_verbose;
-		if (strncasecmp(s + 17, "atleast ", 8) == 0) {
-			int tmp;
-			if (sscanf(s + 25, "%d", &tmp) != 1) {
-				fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
-			} else {
-				if (tmp > option_verbose) {
-					option_verbose = tmp;
-				}
-				if (old_verbose != option_verbose) {
-					fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
-				} else {
-					fprintf(stdout, "Verbosity level unchanged.\n");
-				}
+	} else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
+	    (s[4] == '\0' || isspace(s[4]))) {
+		quit_handler(0, SHUTDOWN_FAST, 0);
+		ret = 1;
+	} else if (s[0]) {
+		char *shrunk = ast_strdupa(s);
+		char *cur;
+		char *prev;
+
+		/*
+		 * Remove duplicate spaces from shrunk for matching purposes.
+		 *
+		 * shrunk has at least one character in it to start with or we
+		 * couldn't get here.
+		 */
+		for (prev = shrunk, cur = shrunk + 1; *cur; ++cur) {
+			if (*prev == ' ' && *cur == ' ') {
+				/* Skip repeated space delimiter. */
+				continue;
 			}
-		} else {
-			if (sscanf(s + 17, "%d", &option_verbose) != 1) {
-				fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
+			*++prev = *cur;
+		}
+		*++prev = '\0';
+
+		if (strncasecmp(shrunk, "core set verbose ", 17) == 0) {
+			/*
+			 * We need to still set the rasterisk option_verbose in case we are
+			 * talking to an earlier version which doesn't prefilter verbose
+			 * levels.  This is really a compromise as we should always take
+			 * whatever the server sends.
+			 */
+
+			if (!strncasecmp(shrunk + 17, "off", 3)) {
+				ast_verb_console_set(0);
 			} else {
-				if (old_verbose != option_verbose) {
-					fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
-				} else {
-					fprintf(stdout, "Verbosity level unchanged.\n");
+				int verbose_new;
+				int atleast;
+
+				atleast = 8;
+				if (strncasecmp(shrunk + 17, "atleast ", atleast)) {
+					atleast = 0;
+				}
+
+				if (sscanf(shrunk + 17 + atleast, "%30d", &verbose_new) == 1) {
+					if (!atleast || ast_verb_console_get() < verbose_new) {
+						ast_verb_console_set(verbose_new);
+					}
 				}
 			}
 		}
-		ret = 1;
-	} else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
-	    (s[4] == '\0' || isspace(s[4]))) {
-		quit_handler(0, SHUTDOWN_FAST, 0);
-		ret = 1;
 	}
 
 	return ret;
@@ -2426,6 +2472,31 @@ static struct ast_cli_entry cli_asterisk[] = {
 #endif /* ! LOW_MEMORY */
 };
 
+static void send_rasterisk_connect_commands(void)
+{
+	char buf[80];
+
+	/*
+	 * Tell the server asterisk instance about the verbose level
+	 * initially desired.
+	 */
+	if (option_verbose) {
+		snprintf(buf, sizeof(buf), "core set verbose atleast %d silent", option_verbose);
+		fdsend(ast_consock, buf);
+	}
+
+	if (option_debug) {
+		snprintf(buf, sizeof(buf), "core set debug atleast %d", option_debug);
+		fdsend(ast_consock, buf);
+	}
+
+	if (!ast_opt_mute) {
+		fdsend(ast_consock, "logger mute silent");
+	} else {
+		printf("log and verbose output currently muted ('logger mute' to unmute)\n");
+	}
+}
+
 static int ast_el_read_char(EditLine *editline, char *cp)
 {
 	int num_read = 0;
@@ -2479,10 +2550,7 @@ static int ast_el_read_char(EditLine *editline, char *cp)
 							fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
 							printf("%s", term_quit());
 							WELCOME_MESSAGE;
-							if (!ast_opt_mute)
-								fdsend(ast_consock, "logger mute silent");
-							else
-								printf("log and verbose output currently muted ('logger mute' to unmute)\n");
+							send_rasterisk_connect_commands();
 							break;
 						} else
 							usleep(1000000 / reconnects_per_second);
@@ -3023,11 +3091,7 @@ static void ast_remotecontrol(char *data)
 	else
 		pid = -1;
 	if (!data) {
-		if (!ast_opt_mute) {
-			fdsend(ast_consock, "logger mute silent");
-		} else {
-			printf("log and verbose output currently muted ('logger mute' to unmute)\n");
-		}
+		send_rasterisk_connect_commands();
 	}
 
 	if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
@@ -3502,6 +3566,7 @@ static void canary_exit(void)
 		kill(canary_pid, SIGKILL);
 }
 
+/* Execute CLI commands on startup.  Run by main() thread. */
 static void run_startup_commands(void)
 {
 	int fd;
@@ -3930,6 +3995,9 @@ int main(int argc, char *argv[])
 		}
 	}
 
+	/* Initial value of the maximum active system verbosity level. */
+	ast_verb_sys_level = option_verbose;
+
 	if (ast_tryconnect()) {
 		/* One is already running */
 		if (ast_opt_remote) {
diff --git a/main/cli.c b/main/cli.c
index aeec29998c3177aaac51870c3b6f20d702a13e2a..ef5300e411ddfc1adb4db9cfa214a22baca053a4 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -94,8 +94,6 @@ AST_RWLIST_HEAD(module_level_list, module_level);
 
 /*! list of module names and their debug levels */
 static struct module_level_list debug_modules = AST_RWLIST_HEAD_INIT_VALUE;
-/*! list of module names and their verbose levels */
-static struct module_level_list verbose_modules = AST_RWLIST_HEAD_INIT_VALUE;
 
 AST_THREADSTORAGE(ast_cli_buf);
 
@@ -139,19 +137,7 @@ unsigned int ast_debug_get_by_module(const char *module)
 
 unsigned int ast_verbose_get_by_module(const char *module)
 {
-	struct module_level *ml;
-	unsigned int res = 0;
-
-	AST_RWLIST_RDLOCK(&verbose_modules);
-	AST_LIST_TRAVERSE(&verbose_modules, ml, entry) {
-		if (!strcasecmp(ml->module, module)) {
-			res = ml->level;
-			break;
-		}
-	}
-	AST_RWLIST_UNLOCK(&verbose_modules);
-
-	return res;
+	return 0;
 }
 
 /*! \internal
@@ -329,14 +315,19 @@ static char *handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli
 
 	return CLI_SUCCESS;
 }
+
 /*!
- * \brief Find the debug or verbose file setting
- * \arg debug 1 for debug, 0 for verbose
+ * \brief Find the module level setting
+ *
+ * \param module Module name to look for.
+ * \param mll List to search.
+ *
+ * \retval level struct found on success.
+ * \retval NULL not found.
  */
-static struct module_level *find_module_level(const char *module, unsigned int debug)
+static struct module_level *find_module_level(const char *module, struct module_level_list *mll)
 {
 	struct module_level *ml;
-	struct module_level_list *mll = debug ? &debug_modules : &verbose_modules;
 
 	AST_LIST_TRAVERSE(mll, ml, entry) {
 		if (!strcasecmp(ml->module, module))
@@ -386,52 +377,77 @@ static char *complete_number(const char *partial, unsigned int min, unsigned int
 	return NULL;
 }
 
-static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static void status_debug_verbose(struct ast_cli_args *a, const char *what, int old_val, int cur_val)
+{
+	char was_buf[30];
+	const char *was;
+
+	if (old_val) {
+		snprintf(was_buf, sizeof(was_buf), "%d", old_val);
+		was = was_buf;
+	} else {
+		was = "OFF";
+	}
+
+	if (old_val == cur_val) {
+		ast_cli(a->fd, "%s is still %s.\n", what, was);
+	} else {
+		char now_buf[30];
+		const char *now;
+
+		if (cur_val) {
+			snprintf(now_buf, sizeof(now_buf), "%d", cur_val);
+			now = now_buf;
+		} else {
+			now = "OFF";
+		}
+
+		ast_cli(a->fd, "%s was %s and is now %s.\n", what, was, now);
+	}
+}
+
+static char *handle_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	int oldval;
 	int newlevel;
-	unsigned int is_debug;
 	int atleast = 0;
-	int fd = a->fd;
-	int argc = a->argc;
-	const char * const *argv = a->argv;
 	const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
-	int *dst;
-	char *what;
-	struct module_level_list *mll;
 	struct module_level *ml;
 
 	switch (cmd) {
 	case CLI_INIT:
-		e->command = "core set {debug|verbose}";
+		e->command = "core set debug";
 		e->usage =
 #if !defined(LOW_MEMORY)
-			"Usage: core set {debug|verbose} [atleast] <level> [module]\n"
+			"Usage: core set debug [atleast] <level> [module]\n"
 #else
-			"Usage: core set {debug|verbose} [atleast] <level>\n"
+			"Usage: core set debug [atleast] <level>\n"
 #endif
-			"       core set {debug|verbose} off\n"
+			"       core set debug off\n"
+			"\n"
 #if !defined(LOW_MEMORY)
-			"       Sets level of debug or verbose messages to be displayed or\n"
+			"       Sets level of debug messages to be displayed or\n"
 			"       sets a module name to display debug messages from.\n"
 #else
-			"       Sets level of debug or verbose messages to be displayed.\n"
+			"       Sets level of debug messages to be displayed.\n"
 #endif
-			"	0 or off means no messages should be displayed.\n"
-			"	Equivalent to -d[d[...]] or -v[v[v...]] on startup\n";
+			"       0 or off means no messages should be displayed.\n"
+			"       Equivalent to -d[d[...]] on startup\n";
 		return NULL;
 
 	case CLI_GENERATE:
-		if (a->pos == 3 || (a->pos == 4 && !strcasecmp(a->argv[3], "atleast"))) {
+		if (!strcasecmp(argv3, "atleast")) {
+			atleast = 1;
+		}
+		if (a->pos == 3 || (a->pos == 4 && atleast)) {
 			const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
 			int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
+
 			if (a->n < 21 && numbermatch == 0) {
 				return complete_number(pos, 0, 0x7fffffff, a->n);
 			} else if (pos[0] == '0') {
 				if (a->n == 0) {
 					return ast_strdup("0");
-				} else {
-					return NULL;
 				}
 			} else if (a->n == (21 - numbermatch)) {
 				if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
@@ -443,8 +459,11 @@ static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 				return ast_strdup("atleast");
 			}
 #if !defined(LOW_MEMORY)
-		} else if (a->pos == 4 || (a->pos == 5 && !strcasecmp(argv3, "atleast"))) {
-			return ast_complete_source_filename(a->pos == 4 ? S_OR(a->argv[4], "") : S_OR(a->argv[5], ""), a->n);
+		} else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off"))
+			|| (a->pos == 5 && atleast)) {
+			const char *pos = S_OR(a->argv[a->pos], "");
+
+			return ast_complete_source_filename(pos, a->n);
 #endif
 		}
 		return NULL;
@@ -453,117 +472,200 @@ static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 	 * we are guaranteed to be called with argc >= e->args;
 	 */
 
-	if (argc <= e->args)
+	if (a->argc <= e->args) {
 		return CLI_SHOWUSAGE;
-	if (!strcasecmp(argv[e->args - 1], "debug")) {
-		dst = &option_debug;
-		oldval = option_debug;
-		what = "Core debug";
-		is_debug = 1;
-	} else {
-		dst = &option_verbose;
-		oldval = option_verbose;
-		what = "Verbosity";
-		is_debug = 0;
 	}
-	if (argc == e->args + 1 && !strcasecmp(argv[e->args], "off")) {
+
+	if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args], "off")) {
 		newlevel = 0;
+	} else {
+		if (!strcasecmp(a->argv[e->args], "atleast")) {
+			atleast = 1;
+		}
+		if (a->argc != e->args + atleast + 1 && a->argc != e->args + atleast + 2) {
+			return CLI_SHOWUSAGE;
+		}
+		if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {
+			return CLI_SHOWUSAGE;
+		}
 
-		mll = is_debug ? &debug_modules : &verbose_modules;
+		if (a->argc == e->args + atleast + 2) {
+			/* We have specified a module name. */
+			char *mod = ast_strdupa(a->argv[e->args + atleast + 1]);
+			int mod_len = strlen(mod);
 
-		AST_RWLIST_WRLOCK(mll);
-		while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
-			ast_free(ml);
-		}
-		ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
-		AST_RWLIST_UNLOCK(mll);
+			if (3 < mod_len && !strcasecmp(mod + mod_len - 3, ".so")) {
+				mod[mod_len - 3] = '\0';
+			}
 
-		goto done;
+			AST_RWLIST_WRLOCK(&debug_modules);
+
+			ml = find_module_level(mod, &debug_modules);
+			if (!newlevel) {
+				if (!ml) {
+					/* Specified off for a nonexistent entry. */
+					AST_RWLIST_UNLOCK(&debug_modules);
+					ast_cli(a->fd, "Core debug is still 0 for '%s'.\n", mod);
+					return CLI_SUCCESS;
+				}
+				AST_RWLIST_REMOVE(&debug_modules, ml, entry);
+				if (AST_RWLIST_EMPTY(&debug_modules)) {
+					ast_clear_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);
+				}
+				AST_RWLIST_UNLOCK(&debug_modules);
+				ast_cli(a->fd, "Core debug was %d and has been set to 0 for '%s'.\n",
+					ml->level, mod);
+				ast_free(ml);
+				return CLI_SUCCESS;
+			}
+
+			if (ml) {
+				if ((atleast && newlevel < ml->level) || ml->level == newlevel) {
+					ast_cli(a->fd, "Core debug is still %d for '%s'.\n", ml->level, mod);
+					AST_RWLIST_UNLOCK(&debug_modules);
+					return CLI_SUCCESS;
+				}
+				oldval = ml->level;
+				ml->level = newlevel;
+			} else {
+				ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);
+				if (!ml) {
+					AST_RWLIST_UNLOCK(&debug_modules);
+					return CLI_FAILURE;
+				}
+				oldval = ml->level;
+				ml->level = newlevel;
+				strcpy(ml->module, mod);
+				AST_RWLIST_INSERT_TAIL(&debug_modules, ml, entry);
+			}
+			ast_set_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);
+
+			ast_cli(a->fd, "Core debug was %d and has been set to %d for '%s'.\n",
+				oldval, ml->level, ml->module);
+
+			AST_RWLIST_UNLOCK(&debug_modules);
+
+			return CLI_SUCCESS;
+		}
 	}
-	if (!strcasecmp(argv[e->args], "atleast"))
-		atleast = 1;
-	if (argc != e->args + atleast + 1 && argc != e->args + atleast + 2)
-		return CLI_SHOWUSAGE;
-	if (sscanf(argv[e->args + atleast], "%30d", &newlevel) != 1)
-		return CLI_SHOWUSAGE;
-	if (argc == e->args + atleast + 2) {
-		/* We have specified a module name. */
-		char *mod = ast_strdupa(argv[e->args + atleast + 1]);
 
-		if ((strlen(mod) > 3) && !strcasecmp(mod + strlen(mod) - 3, ".so")) {
-			mod[strlen(mod) - 3] = '\0';
+	/* Update global debug level */
+	if (!newlevel) {
+		/* Specified level was 0 or off. */
+		AST_RWLIST_WRLOCK(&debug_modules);
+		while ((ml = AST_RWLIST_REMOVE_HEAD(&debug_modules, entry))) {
+			ast_free(ml);
 		}
+		ast_clear_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);
+		AST_RWLIST_UNLOCK(&debug_modules);
+	}
+	oldval = option_debug;
+	if (!atleast || newlevel > option_debug) {
+		option_debug = newlevel;
+	}
 
-		mll = is_debug ? &debug_modules : &verbose_modules;
+	/* Report debug level status */
+	status_debug_verbose(a, "Core debug", oldval, option_debug);
 
-		AST_RWLIST_WRLOCK(mll);
+	return CLI_SUCCESS;
+}
 
-		ml = find_module_level(mod, is_debug);
-		if (!newlevel) {
-			if (!ml) {
-				/* Specified off for a nonexistent entry. */
-				AST_RWLIST_UNLOCK(mll);
-				return CLI_SUCCESS;
-			}
-			AST_RWLIST_REMOVE(mll, ml, entry);
-			if (AST_RWLIST_EMPTY(mll))
-				ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
-			AST_RWLIST_UNLOCK(mll);
-			ast_cli(fd, "%s was %d and has been set to 0 for '%s'\n", what, ml->level, mod);
-			ast_free(ml);
-			return CLI_SUCCESS;
+static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	int oldval;
+	int newlevel;
+	int atleast = 0;
+	int silent = 0;
+	const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "core set verbose";
+		e->usage =
+			"Usage: core set verbose [atleast] <level> [silent]\n"
+			"       core set verbose off\n"
+			"\n"
+			"       Sets level of verbose messages to be displayed.\n"
+			"       0 or off means no verbose messages should be displayed.\n"
+			"       The silent option means the command does not report what\n"
+			"       happened to the verbose level.\n"
+			"       Equivalent to -v[v[...]] on startup\n";
+		return NULL;
+
+	case CLI_GENERATE:
+		if (!strcasecmp(argv3, "atleast")) {
+			atleast = 1;
 		}
+		if (a->pos == 3 || (a->pos == 4 && atleast)) {
+			const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
+			int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
 
-		if (ml) {
-			if ((atleast && newlevel < ml->level) || ml->level == newlevel) {
-				ast_cli(fd, "%s is %d for '%s'\n", what, ml->level, mod);
-				AST_RWLIST_UNLOCK(mll);
-				return CLI_SUCCESS;
+			if (a->n < 21 && numbermatch == 0) {
+				return complete_number(pos, 0, 0x7fffffff, a->n);
+			} else if (pos[0] == '0') {
+				if (a->n == 0) {
+					return ast_strdup("0");
+				}
+			} else if (a->n == (21 - numbermatch)) {
+				if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
+					return ast_strdup("off");
+				} else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {
+					return ast_strdup("atleast");
+				}
+			} else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {
+				return ast_strdup("atleast");
 			}
-			oldval = ml->level;
-			ml->level = newlevel;
-		} else {
-			ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);
-			if (!ml) {
-				AST_RWLIST_UNLOCK(mll);
-				return CLI_FAILURE;
+		} else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off"))
+			|| (a->pos == 5 && atleast)) {
+			const char *pos = S_OR(a->argv[a->pos], "");
+
+			if (a->n == 0 && !strncasecmp(pos, "silent", strlen(pos))) {
+				return ast_strdup("silent");
 			}
-			oldval = ml->level;
-			ml->level = newlevel;
-			strcpy(ml->module, mod);
-			AST_RWLIST_INSERT_TAIL(mll, ml, entry);
 		}
+		return NULL;
+	}
+	/* all the above return, so we proceed with the handler.
+	 * we are guaranteed to be called with argc >= e->args;
+	 */
 
-		ast_set_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
+	if (a->argc <= e->args) {
+		return CLI_SHOWUSAGE;
+	}
 
-		AST_RWLIST_UNLOCK(mll);
+	if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args], "off")) {
+		newlevel = 0;
+	} else {
+		if (!strcasecmp(a->argv[e->args], "atleast")) {
+			atleast = 1;
+		}
+		if (a->argc == e->args + atleast + 2
+			&& !strcasecmp(a->argv[e->args + atleast + 1], "silent")) {
+			silent = 1;
+		}
+		if (a->argc != e->args + atleast + silent + 1) {
+			return CLI_SHOWUSAGE;
+		}
+		if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {
+			return CLI_SHOWUSAGE;
+		}
+	}
 
-		ast_cli(fd, "%s was %d and has been set to %d for '%s'\n", what, oldval, ml->level, ml->module);
+	/* Update verbose level */
+	oldval = ast_verb_console_get();
+	if (!atleast || newlevel > oldval) {
+		ast_verb_console_set(newlevel);
+	} else {
+		newlevel = oldval;
+	}
 
+	if (silent) {
+		/* Be silent after setting the level. */
 		return CLI_SUCCESS;
-	} else if (!newlevel) {
-		/* Specified level as 0 instead of off. */
-		mll = is_debug ? &debug_modules : &verbose_modules;
-
-		AST_RWLIST_WRLOCK(mll);
-		while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
-			ast_free(ml);
-		}
-		ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
-		AST_RWLIST_UNLOCK(mll);
 	}
 
-done:
-	if (!atleast || newlevel > *dst)
-		*dst = newlevel;
-	if (oldval > 0 && *dst == 0)
-		ast_cli(fd, "%s is now OFF\n", what);
-	else if (*dst > 0) {
-		if (oldval == *dst)
-			ast_cli(fd, "%s is at least %d\n", what, *dst);
-		else
-			ast_cli(fd, "%s was %d and is now %d\n", what, oldval, *dst);
-	}
+	/* Report verbose level status */
+	status_debug_verbose(a, "Console verbose", oldval, newlevel);
 
 	return CLI_SUCCESS;
 }
@@ -1691,7 +1793,8 @@ static struct ast_cli_entry cli_cli[] = {
 
 	AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),
 
-	AST_CLI_DEFINE(handle_verbose, "Set level of debug/verbose chattiness"),
+	AST_CLI_DEFINE(handle_debug, "Set level of debug chattiness"),
+	AST_CLI_DEFINE(handle_verbose, "Set level of verbose chattiness"),
 
 	AST_CLI_DEFINE(group_show_channels, "Display active channels with group(s)"),
 
diff --git a/main/logger.c b/main/logger.c
index 03db0f458fc150afdf24b66584251e07661a7fab..5134cad6ef0eddf70fe1bbaadaff6a4d47d858fa 100644
--- a/main/logger.c
+++ b/main/logger.c
@@ -118,7 +118,7 @@ struct logchannel {
 	int disabled;
 	/*! syslog facility */
 	int facility;
-	/*! Verbosity level */
+	/*! Verbosity level. (-1 if use option_verbose for the level.) */
 	int verbosity;
 	/*! Type of log channel */
 	enum logtypes type;
@@ -237,32 +237,48 @@ AST_THREADSTORAGE(log_buf);
 
 static void logger_queue_init(void);
 
-static unsigned int make_components(const char *s, int lineno, int *verbosity)
+static void make_components(struct logchannel *chan)
 {
 	char *w;
-	unsigned int res = 0;
-	char *stringp = ast_strdupa(s);
+	unsigned int logmask = 0;
+	char *stringp = ast_strdupa(chan->components);
 	unsigned int x;
+	int verb_level;
 
-	*verbosity = 3;
+	/* Default to using option_verbose as the verbosity level of the logging channel.  */
+	verb_level = -1;
 
 	while ((w = strsep(&stringp, ","))) {
-		w = ast_skip_blanks(w);
-
+		w = ast_strip(w);
+		if (ast_strlen_zero(w)) {
+			continue;
+		}
 		if (!strcmp(w, "*")) {
-			res = 0xFFFFFFFF;
-			break;
-		} else if (!strncasecmp(w, "verbose(", 8) && sscanf(w + 8, "%d)", verbosity) == 1) {
-			res |= (1 << __LOG_VERBOSE);
-		} else for (x = 0; x < ARRAY_LEN(levels); x++) {
-			if (levels[x] && !strcasecmp(w, levels[x])) {
-				res |= (1 << x);
-				break;
+			logmask = 0xFFFFFFFF;
+		} else if (!strncasecmp(w, "verbose(", 8)) {
+			if (levels[__LOG_VERBOSE] && sscanf(w + 8, "%30u)", &verb_level) == 1) {
+				logmask |= (1 << __LOG_VERBOSE);
+			}
+		} else {
+			for (x = 0; x < ARRAY_LEN(levels); ++x) {
+				if (levels[x] && !strcasecmp(w, levels[x])) {
+					logmask |= (1 << x);
+					break;
+				}
 			}
 		}
 	}
-
-	return res;
+	if (chan->type == LOGTYPE_CONSOLE) {
+		/*
+		 * Force to use the root console verbose level so if the
+		 * user specified any verbose level then it does not interfere
+		 * with calculating the ast_verb_sys_level value.
+		 */
+		chan->verbosity = -1;
+	} else {
+		chan->verbosity = verb_level;
+	}
+	chan->logmask = logmask;
 }
 
 static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno)
@@ -332,7 +348,7 @@ static struct logchannel *make_logchannel(const char *channel, const char *compo
 		}
 		chan->type = LOGTYPE_FILE;
 	}
-	chan->logmask = make_components(chan->components, lineno, &chan->verbosity);
+	make_components(chan);
 
 	return chan;
 }
@@ -829,10 +845,12 @@ static int reload_logger(int rotate, const char *altconf)
 	if (logfiles.queue_log) {
 		res = logger_queue_restart(queue_rotate);
 		AST_RWLIST_UNLOCK(&logchannels);
+		ast_verb_update();
 		ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
 		ast_verb(1, "Asterisk Queue Logger restarted\n");
 	} else {
 		AST_RWLIST_UNLOCK(&logchannels);
+		ast_verb_update();
 	}
 
 	return res;
@@ -1017,12 +1035,6 @@ static void ast_log_vsyslog(struct logmsg *msg)
 	syslog(syslog_level, "%s", buf);
 }
 
-/* These gymnastics are due to platforms which designate char as unsigned by
- * default. Level is the negative character -- offset by 1, because \0 is the
- * EOS delimiter. */
-#define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
-#define VERBOSE_HASMAGIC(x)	(*(signed char *) (x) < 0)
-
 /*! \brief Print a normal log message to the channels */
 static void logger_print_normal(struct logmsg *logmsg)
 {
@@ -1033,7 +1045,9 @@ static void logger_print_normal(struct logmsg *logmsg)
 
 	if (logmsg->level == __LOG_VERBOSE) {
 		char *tmpmsg = ast_strdupa(logmsg->message + 1);
+
 		level = VERBOSE_MAGIC2LEVEL(logmsg->message);
+
 		/* Iterate through the list of verbosers and pass them the log message string */
 		AST_RWLIST_RDLOCK(&verbosers);
 		AST_RWLIST_TRAVERSE(&verbosers, v, list)
@@ -1059,7 +1073,8 @@ static void logger_print_normal(struct logmsg *logmsg)
 			if (chan->disabled) {
 				continue;
 			}
-			if (logmsg->level == __LOG_VERBOSE && level > chan->verbosity) {
+			if (logmsg->level == __LOG_VERBOSE
+				&& (((chan->verbosity < 0) ? option_verbose : chan->verbosity)) < level) {
 				continue;
 			}
 
@@ -1236,6 +1251,7 @@ int init_logger(void)
 
 	/* create log channels */
 	init_logger_chain(0 /* locked */, NULL);
+	ast_verb_update();
 	logger_initialized = 1;
 
 	return 0;
@@ -1886,6 +1902,148 @@ void ast_verbose(const char *fmt, ...)
 	}
 }
 
+/*! Console verbosity level node. */
+struct verb_console {
+	/*! List node link */
+	AST_LIST_ENTRY(verb_console) node;
+	/*! Console verbosity level. */
+	int *level;
+};
+
+/*! Registered console verbosity levels */
+static AST_RWLIST_HEAD_STATIC(verb_consoles, verb_console);
+
+/*! ast_verb_update() reentrancy protection lock. */
+AST_MUTEX_DEFINE_STATIC(verb_update_lock);
+
+void ast_verb_update(void)
+{
+	struct logchannel *log;
+	struct verb_console *console;
+	int verb_level;
+
+	ast_mutex_lock(&verb_update_lock);
+
+	AST_RWLIST_RDLOCK(&verb_consoles);
+
+	/* Default to the root console verbosity. */
+	verb_level = option_verbose;
+
+	/* Determine max remote console level. */
+	AST_LIST_TRAVERSE(&verb_consoles, console, node) {
+		if (verb_level < *console->level) {
+			verb_level = *console->level;
+		}
+	}
+	AST_RWLIST_UNLOCK(&verb_consoles);
+
+	/* Determine max logger channel level. */
+	AST_RWLIST_RDLOCK(&logchannels);
+	AST_RWLIST_TRAVERSE(&logchannels, log, list) {
+		if (verb_level < log->verbosity) {
+			verb_level = log->verbosity;
+		}
+	}
+	AST_RWLIST_UNLOCK(&logchannels);
+
+	ast_verb_sys_level = verb_level;
+
+	ast_mutex_unlock(&verb_update_lock);
+}
+
+/*!
+ * \internal
+ * \brief Unregister a console verbose level.
+ *
+ * \param console Which console to unregister.
+ *
+ * \return Nothing
+ */
+static void verb_console_unregister(struct verb_console *console)
+{
+	AST_RWLIST_WRLOCK(&verb_consoles);
+	console = AST_RWLIST_REMOVE(&verb_consoles, console, node);
+	AST_RWLIST_UNLOCK(&verb_consoles);
+	if (console) {
+		ast_verb_update();
+	}
+}
+
+static void verb_console_free(void *v_console)
+{
+	struct verb_console *console = v_console;
+
+	verb_console_unregister(console);
+	ast_free(console);
+}
+
+/*! Thread specific console verbosity level node. */
+AST_THREADSTORAGE_CUSTOM(my_verb_console, NULL, verb_console_free);
+
+void ast_verb_console_register(int *level)
+{
+	struct verb_console *console;
+
+	console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+	if (!console || !level) {
+		return;
+	}
+	console->level = level;
+
+	AST_RWLIST_WRLOCK(&verb_consoles);
+	AST_RWLIST_INSERT_HEAD(&verb_consoles, console, node);
+	AST_RWLIST_UNLOCK(&verb_consoles);
+	ast_verb_update();
+}
+
+void ast_verb_console_unregister(void)
+{
+	struct verb_console *console;
+
+	console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+	if (!console) {
+		return;
+	}
+	verb_console_unregister(console);
+}
+
+int ast_verb_console_get(void)
+{
+	struct verb_console *console;
+	int verb_level;
+
+	console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+	AST_RWLIST_RDLOCK(&verb_consoles);
+	if (!console) {
+		verb_level = 0;
+	} else if (console->level) {
+		verb_level = *console->level;
+	} else {
+		verb_level = option_verbose;
+	}
+	AST_RWLIST_UNLOCK(&verb_consoles);
+	return verb_level;
+}
+
+void ast_verb_console_set(int verb_level)
+{
+	struct verb_console *console;
+
+	console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+	if (!console) {
+		return;
+	}
+
+	AST_RWLIST_WRLOCK(&verb_consoles);
+	if (console->level) {
+		*console->level = verb_level;
+	} else {
+		option_verbose = verb_level;
+	}
+	AST_RWLIST_UNLOCK(&verb_consoles);
+	ast_verb_update();
+}
+
 int ast_register_verbose(void (*v)(const char *string))
 {
 	struct verb *verb;
@@ -1929,7 +2087,7 @@ static void update_logchannels(void)
 	global_logmask = 0;
 
 	AST_RWLIST_TRAVERSE(&logchannels, cur, list) {
-		cur->logmask = make_components(cur->components, cur->lineno, &cur->verbosity);
+		make_components(cur);
 		global_logmask |= cur->logmask;
 	}
 
diff --git a/main/manager.c b/main/manager.c
index a0abedda04940d76a311df9fcfbf489992859d4e..3de1cc7d5f60fed78cf1c29e26564f79b502bec1 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -1588,13 +1588,13 @@ static struct ast_manager_user *get_manager_by_name_locked(const char *name)
  *  \param session manager session to get parameter from.
  *  \return displayconnects config option value.
  */
-static int manager_displayconnects (struct mansession_session *session)
+static int manager_displayconnects(struct mansession_session *session)
 {
 	struct ast_manager_user *user = NULL;
 	int ret = 0;
 
 	AST_RWLIST_RDLOCK(&users);
-	if ((user = get_manager_by_name_locked (session->username))) {
+	if ((user = get_manager_by_name_locked(session->username))) {
 		ret = user->displayconnects;
 	}
 	AST_RWLIST_UNLOCK(&users);
@@ -5581,7 +5581,9 @@ static void purge_sessions(int n_max)
 	while ((session = ao2_iterator_next(&i)) && n_max > 0) {
 		ao2_lock(session);
 		if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
-			if (session->authenticated && manager_displayconnects(session)) {
+			if (session->authenticated
+				&& VERBOSITY_ATLEAST(2)
+				&& manager_displayconnects(session)) {
 				ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
 					session->username, ast_sockaddr_stringify_addr(&session->addr));
 			}
diff --git a/main/pbx.c b/main/pbx.c
index d3f740925e83aa477de4de7f77b551737a8fee52..fa0d8364e3dace81abfa0b0410879d70816392d7 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -4884,7 +4884,7 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
 			ast_channel_trace_update(c);
 #endif
 			ast_debug(1, "Launching '%s'\n", app->name);
-			{
+			if (VERBOSITY_ATLEAST(3)) {
 				char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
 				ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
 					exten, context, priority,