diff --git a/CHANGES b/CHANGES
index 839744206a..350c00c55d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -77,6 +77,12 @@ app_confbridge
     instance, allows a channel to immediately exit the ConfBridge without having
     to wait for a leave announcement to play.
 
+Core
+------------------
+  * If Asterisk is built with systemd support, and run under systemd, it will
+    notify systemd of its state using sd_notify. Use 'Type=notify' in
+    asterisk.service.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13 to Asterisk 14 --------------------
 ------------------------------------------------------------------------------
diff --git a/configure b/configure
index 04613c38f9..c9cd624baa 100755
--- a/configure
+++ b/configure
@@ -639,6 +639,11 @@ PBX_SYSLOG_FACILITY_LOG_DAEMON
 PBX_SYSLOG_FACILITY_LOG_CRON
 PBX_SYSLOG_FACILITY_LOG_AUTHPRIV
 PBX_SYSLOG_FACILITY_LOG_AUTH
+SYSTEMD_LIBS
+SYSTEMD_CFLAGS
+SYSTEMD_INCLUDE
+SYSTEMD_LIB
+PBX_SYSTEMD
 PBX_GENERIC_ODBC
 GENERIC_ODBC_INCLUDE
 GENERIC_ODBC_LIB
@@ -1316,6 +1321,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -1455,7 +1461,9 @@ PYTHONDEV_LIBS
 GMIME_CFLAGS
 GMIME_LIBS
 GTK2_CFLAGS
-GTK2_LIBS'
+GTK2_LIBS
+SYSTEMD_CFLAGS
+SYSTEMD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1494,6 +1502,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1746,6 +1755,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1883,7 +1901,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -2036,6 +2054,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -2207,6 +2226,10 @@ Some influential environment variables:
   GMIME_LIBS  linker flags for GMIME, overriding pkg-config
   GTK2_CFLAGS C compiler flags for GTK2, overriding pkg-config
   GTK2_LIBS   linker flags for GTK2, overriding pkg-config
+  SYSTEMD_CFLAGS
+              C compiler flags for SYSTEMD, overriding pkg-config
+  SYSTEMD_LIBS
+              linker flags for SYSTEMD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -34668,6 +34691,98 @@ fi
 
 
 
+
+
+
+
+   if test "x${PBX_SYSTEMD}" != "x1" -a "${USE_SYSTEMD}" != "no"; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD" >&5
+$as_echo_n "checking for SYSTEMD... " >&6; }
+
+if test -n "$SYSTEMD_CFLAGS"; then
+    pkg_cv_SYSTEMD_CFLAGS="$SYSTEMD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SYSTEMD_CFLAGS=`$PKG_CONFIG --cflags "libsystemd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$SYSTEMD_LIBS"; then
+    pkg_cv_SYSTEMD_LIBS="$SYSTEMD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SYSTEMD_LIBS=`$PKG_CONFIG --libs "libsystemd" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsystemd" 2>&1`
+        else
+	        SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsystemd" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$SYSTEMD_PKG_ERRORS" >&5
+
+
+            PBX_SYSTEMD=0
+
+
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+            PBX_SYSTEMD=0
+
+
+else
+	SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS
+	SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+            PBX_SYSTEMD=1
+            SYSTEMD_INCLUDE="$SYSTEMD_CFLAGS"
+            SYSTEMD_LIB="$SYSTEMD_LIBS"
+
+$as_echo "#define HAVE_SYSTEMD 1" >>confdefs.h
+
+
+fi
+   fi
+
+
 PBX_SYSLOG=0
 
 if test "${ac_cv_header_syslog_h}" = "yes"; then
diff --git a/configure.ac b/configure.ac
index 54e612ca1b..912de6ba9a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2627,6 +2627,11 @@ AC_SUBST([GENERIC_ODBC_LIB])
 AC_SUBST([GENERIC_ODBC_INCLUDE])
 AC_SUBST([PBX_GENERIC_ODBC])
 
+AC_SUBST([PBX_SYSTEMD])
+AC_SUBST([SYSTEMD_LIB])
+AC_SUBST([SYSTEMD_INCLUDE])
+AST_PKG_CONFIG_CHECK([SYSTEMD], [libsystemd])
+
 PBX_SYSLOG=0
 
 if test "${ac_cv_header_syslog_h}" = "yes"; then
diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in
index 08c68c1cc3..efba81249f 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -1024,6 +1024,9 @@
 /* Define to 1 if you have the <syslog.h> header file. */
 #undef HAVE_SYSLOG_H
 
+/* Define if your system has the SYSTEMD libraries. */
+#undef HAVE_SYSTEMD
+
 /* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
    */
 #undef HAVE_SYS_DIR_H
diff --git a/include/asterisk/io.h b/include/asterisk/io.h
index 2bddd3780b..6ee8450bd7 100644
--- a/include/asterisk/io.h
+++ b/include/asterisk/io.h
@@ -139,6 +139,16 @@ int ast_restore_tty(int fd, int oldstatus);
 
 int ast_get_termcols(int fd);
 
+/*!
+ * \brief a wrapper for sd_notify(): notify systemd of any state changes.
+ * \param state a string that states the changes. See sd_notify(3).
+ * The wrapper does nothing if systemd ('s development headers) was not
+ * detected on the system.
+ * \returns >=0 on success, negative value on error.
+ */
+int ast_sd_notify(const char *state);
+
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
diff --git a/main/Makefile b/main/Makefile
index a6c3ab1b87..d41302a7fc 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -45,6 +45,7 @@ AST_LIBS+=$(UUID_LIB)
 AST_LIBS+=$(CRYPT_LIB)
 AST_LIBS+=$(AST_CLANG_BLOCKS_LIBS)
 AST_LIBS+=$(RT_LIB)
+AST_LIBS+=$(SYSTEMD_LIB)
 
 ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc linux-musl kfreebsd-gnu),)
   ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
diff --git a/main/asterisk.c b/main/asterisk.c
index 7b1338c3dc..c9e3b59a5b 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -2039,6 +2039,9 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart)
 		ast_module_shutdown();
 	}
 
+	if (!restart) {
+		ast_sd_notify("STOPPING=1");
+	}
 	if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
 		ast_el_write_default_histfile();
 		if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
@@ -4566,6 +4569,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
 	ast_register_cleanup(main_atexit);
 
 	run_startup_commands();
+	ast_sd_notify("READY=1");
 
 	ast_verb(0, COLORIZE_FMT "\n", COLORIZE(COLOR_BRGREEN, 0, "Asterisk Ready."));
 
diff --git a/main/io.c b/main/io.c
index ff5ca57f79..3441fbae9f 100644
--- a/main/io.c
+++ b/main/io.c
@@ -36,6 +36,9 @@ ASTERISK_REGISTER_FILE()
 
 #include "asterisk/io.h"
 #include "asterisk/utils.h"
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
 
 #ifdef DEBUG_IO
 #define DEBUG DEBUG_M
@@ -384,3 +387,10 @@ int ast_get_termcols(int fd)
 	return cols;
 }
 
+int ast_sd_notify(const char *state) {
+#ifdef HAVE_SYSTEMD
+	return sd_notify(0, state);
+#else
+	return 0;
+#endif
+}
diff --git a/main/loader.c b/main/loader.c
index f959221738..36a3d5f61b 100644
--- a/main/loader.c
+++ b/main/loader.c
@@ -891,6 +891,7 @@ enum ast_module_reload_result ast_module_reload(const char *name)
 		res = AST_MODULE_RELOAD_IN_PROGRESS;
 		goto module_reload_exit;
 	}
+	ast_sd_notify("RELOAD=1");
 	ast_lastreloadtime = ast_tvnow();
 
 	if (ast_opt_lock_confdir) {
@@ -904,9 +905,8 @@ enum ast_module_reload_result ast_module_reload(const char *name)
 		}
 		if (res != AST_LOCK_SUCCESS) {
 			ast_log(AST_LOG_WARNING, "Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
-			ast_mutex_unlock(&reloadlock);
 			res = AST_MODULE_RELOAD_ERROR;
-			goto module_reload_exit;
+			goto module_reload_done;
 		}
 	}
 
@@ -923,8 +923,7 @@ enum ast_module_reload_result ast_module_reload(const char *name)
 		if (ast_opt_lock_confdir) {
 			ast_unlock_path(ast_config_AST_CONFIG_DIR);
 		}
-		ast_mutex_unlock(&reloadlock);
-		goto module_reload_exit;
+		goto module_reload_done;
 	}
 
 	AST_DLLIST_LOCK(&module_list);
@@ -966,7 +965,9 @@ enum ast_module_reload_result ast_module_reload(const char *name)
 	if (ast_opt_lock_confdir) {
 		ast_unlock_path(ast_config_AST_CONFIG_DIR);
 	}
+module_reload_done:
 	ast_mutex_unlock(&reloadlock);
+	ast_sd_notify("READY=1");
 
 module_reload_exit:
 	publish_reload_message(name, res);
diff --git a/makeopts.in b/makeopts.in
index 8583e19465..d674355a9c 100644
--- a/makeopts.in
+++ b/makeopts.in
@@ -256,6 +256,10 @@ RT_LIB=@RT_LIB@
 SS7_INCLUDE=@SS7_INCLUDE@
 SS7_LIB=@SS7_LIB@
 
+HAVE_SYSTEMD=@PBX_SYSTEMD@
+SYSTEMD_INCLUDE=@SYSTEMD_INCLUDE@
+SYSTEMD_LIB=@SYSTEMD_LIB@
+
 OPENR2_INCLUDE=@OPENR2_INCLUDE@
 OPENR2_LIB=@OPENR2_LIB@