diff --git a/discord/ext/commands/bot.py b/discord/ext/commands/bot.py
index 7b6cd6754..2515a8336 100644
--- a/discord/ext/commands/bot.py
+++ b/discord/ext/commands/bot.py
@@ -27,6 +27,8 @@ DEALINGS IN THE SOFTWARE.
 import asyncio
 import discord
 import inspect
+import importlib
+import sys
 
 from .core import GroupMixin, Command
 from .view import StringView
@@ -78,6 +80,7 @@ class Bot(GroupMixin, discord.Client):
         self.command_prefix = command_prefix
         self.extra_events = {}
         self.cogs = {}
+        self.extensions = {}
 
     # internal helpers
 
@@ -262,7 +265,6 @@ class Bot(GroupMixin, discord.Client):
             except ValueError:
                 pass
 
-
     def listen(self, name=None):
         """A decorator that registers another function as an external
         event listener. Basically this allows you to listen to multiple
@@ -375,6 +377,55 @@ class Bot(GroupMixin, discord.Client):
             if name.startswith('on_'):
                 self.remove_listener(member)
 
+    # extensions
+
+    def load_extension(self, name):
+        if name in self.extensions:
+            return
+
+        lib = importlib.import_module(name)
+        try:
+            lib.setup(self)
+        except AttributeError:
+            raise discord.ClientException('extension does not have a setup function')
+
+        self.extensions[name] = lib
+
+    def unload_extension(self, name):
+        lib = self.extensions.get(name)
+        if lib is None:
+            return
+
+        # find all references to the module
+
+        # remove the cogs registered from the module
+        for cogname, cog in self.cogs.copy().items():
+            if cog.__module__ is lib:
+                self.remove_cog(cogname)
+
+        # first remove all the commands from the module
+        for command in self.commands.copy().values():
+            if command.module is lib:
+                command.module = None
+                if isinstance(command, GroupMixin):
+                    command.recursively_remove_all_commands()
+                self.remove_command(command.name)
+
+        # then remove all the listeners from the module
+        for event_list in self.extra_events.copy().values():
+            remove = []
+            for index, event in enumerate(event_list):
+                if inspect.getmodule(event) is lib:
+                    remove.append(index)
+
+            for index in reversed(remove):
+                del event_list[index]
+
+        # finally remove the import..
+        del lib
+        del self.extensions[name]
+        del sys.modules[name]
+
     # command processing
 
     @asyncio.coroutine
diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py
index 14135b084..731bd1875 100644
--- a/discord/ext/commands/core.py
+++ b/discord/ext/commands/core.py
@@ -316,6 +316,12 @@ class GroupMixin:
         self.commands = {}
         super().__init__(**kwargs)
 
+    def recursively_remove_all_commands(self):
+        for command in self.commands.copy().values():
+            if isinstance(command, GroupMixin):
+                command.recursively_remove_all_commands()
+            self.remove_command(command.name)
+
     def add_command(self, command):
         """Adds a :class:`Command` or its superclasses into the internal list
         of commands.