diff --git a/Makefile b/Makefile
index 29a6bbedffbc5d892e7e787e0f81b000147c3952..00f8418c6fe3126ef01102c4d244a50768e893cb 100644
--- a/Makefile
+++ b/Makefile
@@ -689,6 +689,7 @@ samples: adsi
 		echo "                        ; to the device.  It is for this reason that this is optional, as it may result in requiring a" ; \
 		echo "                        ; temporary codec translation path for a channel that may not otherwise require one." ; \
 		echo ";transcode_via_sln = yes ; Build transcode paths via SLINEAR, instead of directly" ; \
+		echo ";sendfullybooted = yes  ; Send the FullyBooted AMI event on AMI login and when all modules are finished loading" ; \
 		echo ";runuser = asterisk ; The user to run as" ; \
 		echo ";rungroup = asterisk ; The group to run as" ; \
 		echo "" ; \
diff --git a/doc/manager_1_1.txt b/doc/manager_1_1.txt
index fc472e8ddfb1a3de4aa0bb5a4d383a03aca71350..500e6b16d58f4d5cab08179d4a42a9023991ae42 100644
--- a/doc/manager_1_1.txt
+++ b/doc/manager_1_1.txt
@@ -181,6 +181,22 @@ Changes to manager version 1.1:
 * NEW EVENTS
 ------------
 
+- Event: FullyBooted
+	Modules: loader.c
+	Purpose:
+		It is handy to have a single event notification for when all Asterisk
+		modules have been loaded--especially for situations like running
+		automated tests. This event will fire 1) immediately upon all modules
+		loading or 2) upon connection to the AMI interface if the modules have
+		already finished loading before the connection was made. This ensures
+		that a user will never miss getting a FullyBooted event. In vary rare
+		circumstances, it might be possible to get two copies of the message
+		if the AMI connection is made right as the modules finish loading.
+	Example:
+		Event: FullyBooted
+		Privilege: system,all
+		Status: Fully Booted
+
 - Event: Transfer
 	Modules: res_features, chan_sip
 	Purpose:
diff --git a/doc/tex/manager.tex b/doc/tex/manager.tex
index 1f9fa1495dab2e4984fcb8f9c7d3619a2d0e5847..7235ca447501599ffa3cdc9898b0d5fec34f4549 100644
--- a/doc/tex/manager.tex
+++ b/doc/tex/manager.tex
@@ -28,8 +28,6 @@ If you develop applications, please try to reuse existing manager
 headers and their interpretation. If you are unsure, discuss on
 the asterisk-dev mailing list.
 
-\section{Device status reports}
-
 Manager subscribes to extension status reports from all channels,
 to be able to generate events when an extension or device changes
 state. The level of details in these events may depend on the channel
@@ -111,6 +109,21 @@ There are a number of GUI tools that use the manager interface, please search
 the mailing list archives and the documentation page on the
 \url{http://www.asterisk.org} web site for more information.
 
+\section{Ensuring all modules are loaded}
+It is possible to connect to the manager interface before all Asterisk modules
+are loaded. To ensure that an application does not send AMI actions that might
+require a module that has not yet loaded, the application can listen for the
+FullyBooted manager event. It will be sent upon connection if all modules have
+been loaded, or as soon as loading is complete. The event:
+
+\begin{verbatim}
+   Event: FullyBooted
+   Privilege: system,all
+   Status: Fully Booted
+\end{verbatim}
+
+\section{Device status reports}
+
 
 \section{Some standard AMI headers}
 \begin{verbatim}
diff --git a/include/asterisk/options.h b/include/asterisk/options.h
index f08b3bcf31219670d180a3c057cd5afd5ade3ed0..ff9b6b28ccab081383cea2f956d61f5ec41c8035 100644
--- a/include/asterisk/options.h
+++ b/include/asterisk/options.h
@@ -82,6 +82,8 @@ enum ast_option_flags {
 	AST_OPT_FLAG_DEBUG_FILE = (1 << 23),
 	/*! There is a per-file verbose setting */
 	AST_OPT_FLAG_VERBOSE_FILE = (1 << 24),
+	/*! Send the FullyBooted AMI event when all modules are loaded */
+	AST_OPT_FLAG_SEND_FULLYBOOTED = (1 << 25),
 };
 
 /*! These are the options that set by default when Asterisk starts */
@@ -111,6 +113,7 @@ enum ast_option_flags {
 #define ast_opt_mute			ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
 #define ast_opt_dbg_file		ast_test_flag(&ast_options, AST_OPT_FLAG_DEBUG_FILE)
 #define ast_opt_verb_file		ast_test_flag(&ast_options, AST_OPT_FLAG_VERBOSE_FILE)
+#define ast_opt_send_fullybooted	ast_test_flag(&ast_options, AST_OPT_FLAG_SEND_FULLYBOOTED)
 
 extern struct ast_flags ast_options;
 
diff --git a/main/asterisk.c b/main/asterisk.c
index e11312dd5283472d12a9c08ac9f1f17ed9d6be74..03eea48abf9409f8f6ea41192fbd4913c67af1f4 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -433,6 +433,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
 	ast_cli(a->fd, "  -------------\n");
 	ast_cli(a->fd, "  Manager (AMI):               %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
 	ast_cli(a->fd, "  Web Manager (AMI/HTTP):      %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
+	ast_cli(a->fd, "  Send Manager FullyBooted:    %s\n", ast_opt_send_fullybooted ? "Enabled" : "Disabled");
 	ast_cli(a->fd, "  Call data records:           %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
 	ast_cli(a->fd, "  Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
 
@@ -2824,6 +2825,8 @@ static void ast_readconfig(void)
 				option_minmemfree = 0;
 			}
 #endif
+		} else if (!strcasecmp(v->name, "sendfullybooted")) {
+			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_SEND_FULLYBOOTED);
 		}
 	}
 	for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
@@ -3501,6 +3504,9 @@ int main(int argc, char *argv[])
 		sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
 
 	ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
+	if (ast_opt_send_fullybooted) {
+		manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
+	}
 
 	ast_process_pending_reloads();
 
diff --git a/main/manager.c b/main/manager.c
index aa42b5c3ed021c9f24fce11ea41e6efff2ecbc03..8ad63f38ffde6ad489954fe7d0dd4a5ea5959b0d 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -1663,6 +1663,9 @@ static int action_login(struct mansession *s, const struct message *m)
 		ast_verb(2, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
 	ast_log(LOG_EVENT, "%sManager '%s' logged on from %s\n", (s->session->managerid ? "HTTP " : ""), s->session->username, ast_inet_ntoa(s->session->sin.sin_addr));
 	astman_send_ack(s, m, "Authentication accepted");
+	if (ast_opt_send_fullybooted && ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
+		manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
+	}
 	return 0;
 }