diff --git a/frontend/src/admin/settings/components/SettingsSlackForm.jsx b/frontend/src/admin/settings/components/SettingsSlackForm.jsx
index c50c9dc1ea02bd78a2ac6dcdaa14c336742a3a8f..f418f769ec55a07f1106b1eac7b3324a22f8f6ca 100644
--- a/frontend/src/admin/settings/components/SettingsSlackForm.jsx
+++ b/frontend/src/admin/settings/components/SettingsSlackForm.jsx
@@ -3,6 +3,7 @@ import React, { Component, PropTypes } from "react";
 import MetabaseAnalytics from "metabase/lib/analytics";
 import MetabaseUtils from "metabase/lib/utils";
 import SettingsEmailFormElement from "./SettingsEmailFormElement.jsx";
+import SettingsSetting from "./SettingsSetting.jsx";
 
 import Icon from "metabase/components/Icon.jsx";
 
@@ -34,7 +35,7 @@ export default class SettingsSlackForm extends Component {
         // this gives us an opportunity to load up our formData with any existing values for elements
         let formData = {};
         this.props.elements.forEach(function(element) {
-            formData[element.key] = element.value;
+            formData[element.key] = element.value || element.defaultValue;
         });
 
         this.setState({formData});
@@ -156,10 +157,22 @@ export default class SettingsSlackForm extends Component {
             let errorMessage = (formErrors && formErrors.elements) ? formErrors.elements[element.key] : validationErrors[element.key],
                 value = formData[element.key] || element.defaultValue;
 
-            return <SettingsEmailFormElement
+            if (element.key === "slack-token") {
+                return (
+                    <SettingsEmailFormElement
                         key={element.key}
                         element={_.extend(element, {value, errorMessage })}
                         handleChangeEvent={this.handleChangeEvent.bind(this)} />
+                );
+            } else if (element.key === "metabot-enabled") {
+                return (
+                    <SettingsSetting
+                        key={element.key}
+                        setting={_.extend(element, {value, errorMessage })}
+                        updateSetting={(setting, value) => this.handleChangeEvent(setting, value)}
+                    />
+                );
+            }
         });
 
         let saveSettingsButtonStates = {
diff --git a/frontend/src/admin/settings/settings.controllers.js b/frontend/src/admin/settings/settings.controllers.js
index e3bceddb7e0a39989a3e1d34049f9eba9d2e546f..31fd80ba337fcf258dbf12f6996d4daa163d25a0 100644
--- a/frontend/src/admin/settings/settings.controllers.js
+++ b/frontend/src/admin/settings/settings.controllers.js
@@ -105,7 +105,15 @@ const SECTIONS = [
                 type: "string",
                 required: true,
                 autoFocus: true
-            }
+            },
+            {
+                key: "metabot-enabled",
+                display_name: "Metabot",
+                type: "boolean",
+                defaultValue: "true",
+                required: true,
+                autoFocus: false
+            },
         ]
     }
 ];
diff --git a/src/metabase/api/slack.clj b/src/metabase/api/slack.clj
index 006e971b2945c20944db1c5219282632d928d320..810b635a94f21fdcd290b0e3f3dc8433babba8ba 100644
--- a/src/metabase/api/slack.clj
+++ b/src/metabase/api/slack.clj
@@ -3,18 +3,20 @@
   (:require [compojure.core :refer [PUT]]
             [metabase.api.common :refer :all]
             [metabase.config :as config]
-            [metabase.integrations.slack :as slack]))
+            [metabase.integrations.slack :as slack]
+            [metabase.models.setting :as setting]))
 
 (defendpoint PUT "/settings"
-  "Update the `slack-token`. You must be a superuser to do this."
-  [:as {{slack-token :slack-token} :body}]
-  {slack-token [Required NonEmptyString]}
+  "Update Slack related settings. You must be a superuser to do this."
+  [:as {{slack-token :slack-token, metabot-enabled :metabot-enabled, :as slack-settings} :body}]
+  {slack-token     [Required NonEmptyString]
+   metabot-enabled [Required]}
   (check-superuser)
   (try
-    ;; just check that channels.list doesn't throw an exception (that the connection works)
+    ;; just check that channels.list doesn't throw an exception (a.k.a. that the token works)
     (when-not config/is-test?
       (slack/GET :channels.list, :exclude_archived 1, :token slack-token))
-    (slack/slack-token slack-token)
+    (setting/set-all slack-settings)
     {:ok true}
     (catch clojure.lang.ExceptionInfo info
       {:status 400, :body (ex-data info)})))
diff --git a/src/metabase/events/metabot_lifecycle.clj b/src/metabase/events/metabot_lifecycle.clj
new file mode 100644
index 0000000000000000000000000000000000000000..bc6406c01499c6322ae0ca1a55b81606441bc0ba
--- /dev/null
+++ b/src/metabase/events/metabot_lifecycle.clj
@@ -0,0 +1,47 @@
+(ns metabase.events.metabot-lifecycle
+  (:require [clojure.core.async :as async]
+            [clojure.tools.logging :as log]
+            [metabase.db :as db]
+            [metabase.driver :as driver]
+            [metabase.events :as events]
+            [metabase.metabot :as metabot]
+            [metabase.models.database :refer [Database]]))
+
+
+(def ^:const ^:private metabot-lifecycle-topics
+  "The `Set` of event topics which are subscribed to for use in metabot lifecycle."
+  #{:settings-update})
+
+(def ^:private metabot-lifecycle-channel
+  "Channel for receiving event notifications we want to subscribe to for metabot lifecycle events."
+  (async/chan))
+
+
+;;; ## ---------------------------------------- EVENT PROCESSING ----------------------------------------
+
+
+(defn process-metabot-lifecycle-event
+  "Handle processing for a single event notification received on the metabot-lifecycle-channel"
+  [metabot-lifecycle-event]
+  ;; try/catch here to prevent individual topic processing exceptions from bubbling up.  better to handle them here.
+  (when-let [{topic :topic object :item} metabot-lifecycle-event]
+    (try
+      ;; if someone updated our slack-token, or metabot was enabled/disabled then react accordingly
+      (let [{:keys [slack-token metabot-enabled]} object]
+        (cond
+          (and (contains? object :metabot-enabled)
+               (not (= "true" metabot-enabled)))   (metabot/stop-metabot!)
+          (and (contains? object :slack-token)
+               (seq slack-token))                  (metabot/start-metabot!)))
+      (catch Throwable e
+        (log/warn (format "Failed to process driver notifications event. %s" topic) e)))))
+
+
+
+;;; ## ---------------------------------------- LIFECYLE ----------------------------------------
+
+
+(defn events-init
+  "Automatically called during startup; start event listener for metabot lifecycle events."
+  []
+  (events/start-event-listener metabot-lifecycle-topics metabot-lifecycle-channel process-metabot-lifecycle-event))
diff --git a/src/metabase/integrations/slack.clj b/src/metabase/integrations/slack.clj
index b72d32181859a061d4bac11622a41aa6df9d2b1c..a27bb56a57a56781b7a006b9755d9231c32d10b3 100644
--- a/src/metabase/integrations/slack.clj
+++ b/src/metabase/integrations/slack.clj
@@ -7,13 +7,7 @@
 
 
 ;; Define a setting which captures our Slack api token
-(defsetting slack-token "Slack API bearer token obtained from https://api.slack.com/web#authentication" nil
-  :setter (fn [new-value]
-            (setting/set* :slack-token new-value)
-            (require 'metabase.metabot)
-            ((ns-resolve 'metabase.metabot (if (seq new-value)
-                                              'start-metabot!
-                                              'stop-metabot!)))))
+(defsetting slack-token "Slack API bearer token obtained from https://api.slack.com/web#authentication" nil)
 
 (def ^:private ^:const ^String slack-api-base-url "https://slack.com/api")
 (def ^:private ^:const ^String files-channel-name "metabase_files")
diff --git a/src/metabase/metabot.clj b/src/metabase/metabot.clj
index c09ebaa2852a3f3d4019d5a4f390c0e87d373c33..339e275cd2ca8944d9790583461ace5d3f60c9b1 100644
--- a/src/metabase/metabot.clj
+++ b/src/metabase/metabot.clj
@@ -13,10 +13,12 @@
             [metabase.api.common :refer [let-404]]
             [metabase.db :refer [sel]]
             [metabase.integrations.slack :as slack]
+            [metabase.models.setting :as setting]
             [metabase.task.send-pulses :as pulses]
             [metabase.util :as u]
             [metabase.util.urls :as urls]))
 
+(setting/defsetting metabot-enabled "Enable Metabot, which lets you search for and view your saved questions directly via Slack." "true")
 
 ;;; # ------------------------------------------------------------ Metabot Command Handlers ------------------------------------------------------------
 
@@ -37,7 +39,6 @@
                           {(if (true? dispatch-token)
                              (keyword symb)
                              dispatch-token) varr}))]
-    (println (u/format-color 'cyan verb) fn-map)
     (fn dispatch*
       ([]
        (keys-description (format "Here's what I can %s:" verb) fn-map))
@@ -147,23 +148,20 @@
     (when-let [tokens (seq (edn/read-string (str "(" (-> s
                                                          (str/replace "“" "\"") ; replace smart quotes
                                                          (str/replace "”" "\"")) ")")))]
-      (println (u/format-color 'magenta tokens))
       (apply apply-metabot-fn tokens))))
 
 
 ;;; # ------------------------------------------------------------ Metabot Input Handling ------------------------------------------------------------
 
 (defn- message->command-str [{:keys [text]}]
-  (u/prog1 (when (seq text)
-             (second (re-matches #"^mea?ta?boa?t\s+(.*)$" text)))
-    (println (u/format-color 'yellow <>))))
+  (when (seq text)
+    (second (re-matches #"^mea?ta?boa?t\s+(.*)$" text))))
 
 (defn- respond-to-message! [message response]
   (when response
     (let [response (if (coll? response) (str "```\n" (u/pprint-to-str response) "```")
                        (str response))]
       (when (seq response)
-        (println (u/format-color 'green response))
         (slack/post-chat-message! (:channel message) response)))))
 
 (defn- handle-slack-message [message]
@@ -181,14 +179,13 @@
 
 (defn- handle-slack-event [socket start-time event]
   (when-not (= socket @websocket)
-    (println "Go home websocket, you're drunk.")
+    (log/debug "Go home websocket, you're drunk.")
     (s/close! socket)
     (throw (Exception.)))
 
   (when-let [event (json/parse-string event keyword)]
     (when (and (human-message? event)
                (> (event-timestamp-ms event) start-time))
-      (println (u/pprint-to-str 'cyan event))
       (binding [*channel-id* (:channel event)]
         (do-async (handle-slack-message event))))))
 
@@ -197,10 +194,8 @@
 
 (defn- connect-websocket! []
   (when-let [websocket-url (slack/websocket-url)]
-    (log/info "Launching MetaBot... 🤖")
     (let [socket @(aleph/websocket-client websocket-url)]
       (reset! websocket socket)
-      (log/info "Connected to WebSocket.")
       (d/catch (s/consume (partial handle-slack-event socket (System/currentTimeMillis))
                           socket)
           (fn [error]
@@ -221,7 +216,6 @@
 (defn- start-websocket-monitor! []
   (future
     (reset! websocket-monitor-thread-id (.getId (Thread/currentThread)))
-    (log/debug "Monitor thread ID ->" (.getId (Thread/currentThread)))
     ;; Every 2 seconds check to see if websocket connection is [still] open, [re-]open it if not
     (loop []
       (Thread/sleep 500)
@@ -229,7 +223,7 @@
         (try
           (when (or (not  @websocket)
                     (s/closed? @websocket))
-            (log/info "MetaBot WebSocket is closed. < Thread" (.getId (Thread/currentThread)) ">")
+            (log/debug "MetaBot WebSocket is closed.  Reconnecting now.")
             (connect-websocket!))
           (catch Throwable e
             (log/error "Error connecting websocket:" (.getMessage e))))
@@ -240,7 +234,8 @@
 
    This will spin up a background thread that opens and maintains a Slack WebSocket connection."
   []
-  (when (slack/slack-token)
+  (when (and (setting/get :slack-token)
+             (= "true" (setting/get :metabot-enabled)))
     (log/info "Starting MetaBot WebSocket monitor thread...")
     (start-websocket-monitor!)))
 
diff --git a/src/metabase/models/setting.clj b/src/metabase/models/setting.clj
index 689c2b8b9bbce6f939dc6bd450fc946a9d296cf9..aa696d5ea94f7ad1b64caf492734a2f4f6ba6950 100644
--- a/src/metabase/models/setting.clj
+++ b/src/metabase/models/setting.clj
@@ -5,6 +5,7 @@
             [korma.core :as k]
             [metabase.config :as config]
             [metabase.db :refer [exists? sel del]]
+            [metabase.events :as events]
             [metabase.models [common :as common]
                              [interface :as i]]
             [metabase.setup :as setup]
@@ -128,7 +129,7 @@
     (if-let [v (clojure.core/get settings k)]
       (set k v)
       (delete k)))
-  settings)
+  (events/publish-event :settings-update settings))
 
 (defn set*
   "Set the value of a `Setting`, deleting it if VALUE is `nil` or an empty string."