diff --git a/loris/__init__.py b/loris/__init__.py
index 8a242cd3..4eb28e38 100644
--- a/loris/__init__.py
+++ b/loris/__init__.py
@@ -1 +1 @@
-__version__ = '2.3.3'
+__version__ = '3.0.0'
diff --git a/loris/img.py b/loris/img.py
index e7e2a757..87cbc911 100644
--- a/loris/img.py
+++ b/loris/img.py
@@ -9,7 +9,7 @@
 
 from loris.identifiers import CacheNamer
 from loris.parameters import RegionParameter, RotationParameter, SizeParameter
-from loris.utils import mkdir_p, safe_rename, symlink
+from loris.utils import safe_rename, symlink
 
 logger = getLogger(__name__)
 
@@ -171,7 +171,7 @@ def get_canonical_cache_path(self, image_request, image_info):
     def create_dir_and_return_file_path(self, image_request, image_info):
         target_fp = self.get_canonical_cache_path(image_request, image_info)
         target_dp = path.dirname(target_fp)
-        mkdir_p(target_dp)
+        os.makedirs(target_dp, exist_ok=True)
         return target_fp
 
     def upsert(self, image_request, temp_fp, image_info):
diff --git a/loris/img_info.py b/loris/img_info.py
index bd198b19..9b74ec4d 100644
--- a/loris/img_info.py
+++ b/loris/img_info.py
@@ -14,7 +14,6 @@
 from loris.identifiers import CacheNamer
 from loris.jp2_extractor import JP2Extractor, JP2ExtractionError
 from loris.loris_exception import ImageInfoException
-from loris.utils import mkdir_p
 
 logger = getLogger(__name__)
 
@@ -353,7 +352,7 @@ def __setitem__(self, ident, info, _to_fs=True):
             # to fs
             logger.debug('ident passed to __setitem__: %s', ident)
             dp = os.path.dirname(info_fp)
-            mkdir_p(dp)
+            os.makedirs(dp, exist_ok=True)
             logger.debug('Created %s', dp)
 
             with open(info_fp, 'w') as f:
diff --git a/loris/resolver.py b/loris/resolver.py
index d9cb0972..99911825 100644
--- a/loris/resolver.py
+++ b/loris/resolver.py
@@ -6,6 +6,7 @@
 import glob
 import json
 from logging import getLogger
+import os
 from os.path import join, exists, dirname, split
 from os import remove
 from shutil import copy
@@ -18,7 +19,7 @@
 from loris import constants
 from loris.identifiers import CacheNamer, IdentRegexChecker
 from loris.loris_exception import ResolverException, ConfigError
-from loris.utils import mkdir_p, safe_rename
+from loris.utils import safe_rename
 from loris.img_info import ImageInfo
 
 
@@ -314,7 +315,7 @@ def copy_to_cache(self, ident):
         assert source_url is not None
 
         cache_dir = self.cache_dir_path(ident)
-        mkdir_p(cache_dir)
+        os.makedirs(cache_dir, exist_ok=True)
 
         with closing(requests.get(source_url, stream=True, **options)) as response:
             if not response.ok:
@@ -531,7 +532,7 @@ def copy_to_cache(self, ident):
         source_fp = self.source_file_path(ident)
         cache_fp = self.cache_file_path(ident)
 
-        mkdir_p(dirname(cache_fp))
+        os.makedirs(dirname(cache_fp), exist_ok=True)
         copy(source_fp, cache_fp)
         logger.info("Copied %s to %s", source_fp, cache_fp)
 
diff --git a/loris/transforms.py b/loris/transforms.py
index 084d0912..700382e9 100644
--- a/loris/transforms.py
+++ b/loris/transforms.py
@@ -2,6 +2,7 @@
 import multiprocessing
 from logging import getLogger
 from math import ceil, log
+import os
 from os import path
 import platform
 import subprocess
@@ -22,7 +23,6 @@
 
 from loris.loris_exception import ConfigError, TransformException
 from loris.parameters import FULL_MODE
-from loris.utils import mkdir_p
 
 logger = getLogger(__name__)
 
@@ -224,7 +224,7 @@ def __init__(self, config):
         self.tmp_dp = config['tmp_dp']
 
         try:
-            mkdir_p(self.tmp_dp)
+            os.makedirs(self.tmp_dp, exist_ok=True)
         except OSError as ose:
             # Almost certainly a permissions error on one of the required dirs
             from sys import exit
diff --git a/loris/user_commands.py b/loris/user_commands.py
old mode 100644
new mode 100755
index 7ee83c27..9a2a213c
--- a/loris/user_commands.py
+++ b/loris/user_commands.py
@@ -2,7 +2,6 @@
 import os
 import shutil
 from configobj import ConfigObj
-from loris.utils import mkdir_p
 
 
 CONFIG_FILE_NAME = 'loris2.conf'
@@ -55,7 +54,7 @@ def _copy_index_and_favicon(config):
     index_target = os.path.join(www_dir, 'index.txt')
     favicon_target_dir = os.path.join(www_dir, 'icons')
     favicon_target = os.path.join(favicon_target_dir, 'favicon.ico')
-    mkdir_p(favicon_target_dir)
+    os.makedirs(favicon_target_dir, exist_ok=True)
     shutil.copyfile(index_src, index_target)
     shutil.copyfile(favicon_src, favicon_target)
 
@@ -74,7 +73,7 @@ def _make_directories(config):
         log_dir,
     ]
     for d in loris_directories:
-        mkdir_p(d)
+        os.makedirs(d, exist_ok=True)
 
 
 def display_default_config_file():
diff --git a/loris/utils.py b/loris/utils.py
index 8753dec5..ec52f6f3 100644
--- a/loris/utils.py
+++ b/loris/utils.py
@@ -8,17 +8,6 @@
 logger = logging.getLogger(__name__)
 
 
-def mkdir_p(path):
-    """Create a directory if it doesn't already exist."""
-    try:
-        os.makedirs(path)
-    except OSError as err:
-        if err.errno == errno.EEXIST:
-            pass
-        else:
-            raise
-
-
 def symlink(src, dst):
     """Create a symlink from ``src`` to ``dst``.
 
@@ -32,7 +21,7 @@ def symlink(src, dst):
             src, dst)
         return
 
-    mkdir_p(os.path.dirname(dst))
+    os.makedirs(os.path.dirname(dst), exist_ok=True)
 
     # Shouldn't be the case, but helps with debugging.
     if os.path.lexists(dst):
diff --git a/loris/webapp.py b/loris/webapp.py
index 9dcf630c..d3b6a860 100755
--- a/loris/webapp.py
+++ b/loris/webapp.py
@@ -35,7 +35,6 @@
     SyntaxException,
     TransformException,
 )
-from loris.utils import mkdir_p
 
 
 getcontext().prec = 25 # Decimal precision. This should be plenty.
@@ -353,7 +352,7 @@ def __init__(self, app_configs={}):
         self.tmp_dp = _loris_config['tmp_dp']
 
         try:
-            mkdir_p(self.tmp_dp)
+            os.makedirs(self.tmp_dp, exist_ok=True)
         except Exception as exc:
             raise ConfigError("Error creating tmp_dp %s: %r" % (self.tmp_dp, exc))
 
diff --git a/tests/utils_t.py b/tests/utils_t.py
index d79773c6..ce799704 100644
--- a/tests/utils_t.py
+++ b/tests/utils_t.py
@@ -6,35 +6,6 @@
 from loris import utils
 
 
-class TestMkdirP:
-
-    def test_creates_directory(self, tmpdir):
-        path = str(tmpdir.join('test_creates_directory'))
-        assert not os.path.exists(path)
-
-        # If we create the directory, it springs into being
-        utils.mkdir_p(path)
-        assert os.path.exists(path)
-
-        # If we try to create the directory a second time, we don't throw
-        # an exception just because it already exists.
-        utils.mkdir_p(path)
-
-    def test_if_error_is_unexpected_then_is_raised(self, tmpdir):
-        """
-        If the error from ``os.makedirs()`` isn't because the directory
-        already exists, we get an error.
-        """
-        path = str(tmpdir.join('test_if_error_is_unexpected_then_is_raised'))
-
-        message = "Exception thrown in utils_t.py for TestMkdirP"
-
-        m = mock.Mock(side_effect=OSError(-1, message))
-        with mock.patch('loris.utils.os.makedirs', m):
-            with pytest.raises(OSError):
-                utils.mkdir_p(path)
-
-
 @pytest.fixture
 def src(tmpdir):
     path = str(tmpdir.join('src.txt'))