diff --git a/daemon/src/account.cpp b/daemon/src/account.cpp
index 51c150dc4a2da564fe9181fce0a00024cc82d199..454bdbf0ca34b2d59abbc39a206fd14254e75c10 100644
--- a/daemon/src/account.cpp
+++ b/daemon/src/account.cpp
@@ -83,6 +83,7 @@ const char * const Account::DEFAULT_USER_AGENT          = PACKAGE_NAME "/" PACKA
 const char * const Account::USER_AGENT_KEY              = "useragent";
 const char * const Account::HAS_CUSTOM_USER_AGENT_KEY   = "hasCustomUserAgent";
 const char * const Account::PRESENCE_MODULE_ENABLED_KEY = "presenceModuleEnabled";
+const char * const Account::UPNP_ENABLED_KEY            = "upnpEnabled";
 
 using std::map;
 using std::string;
@@ -106,6 +107,7 @@ Account::Account(const string &accountID)
     , userAgent_(DEFAULT_USER_AGENT)
     , hasCustomUserAgent_(false)
     , mailBox_()
+    , upnpEnabled_(false)
 {
     std::random_device rdev;
     std::seed_seq seed {rdev(), rdev()};
@@ -194,6 +196,7 @@ void Account::serialize(YAML::Emitter &out)
     out << YAML::Key << USERNAME_KEY << YAML::Value << username_;
     out << YAML::Key << DISPLAY_NAME_KEY << YAML::Value << displayName_;
     out << YAML::Key << HOSTNAME_KEY << YAML::Value << hostname_;
+    out << YAML::Key << UPNP_ENABLED_KEY << YAML::Value << upnpEnabled_;
 }
 
 void Account::unserialize(const YAML::Node &node)
@@ -218,6 +221,8 @@ void Account::unserialize(const YAML::Node &node)
     parseValue(node, USER_AGENT_KEY, userAgent_);
     parseValue(node, RINGTONE_PATH_KEY, ringtonePath_);
     parseValue(node, RINGTONE_ENABLED_KEY, ringtoneEnabled_);
+
+    parseValue(node, UPNP_ENABLED_KEY, upnpEnabled_);
 }
 
 void Account::setAccountDetails(const std::map<std::string, std::string> &details)
@@ -237,6 +242,7 @@ void Account::setAccountDetails(const std::map<std::string, std::string> &detail
         parseString(details, Conf::CONFIG_ACCOUNT_USERAGENT, userAgent_);
     else
         userAgent_ = DEFAULT_USER_AGENT;
+    parseBool(details, Conf::CONFIG_UPNP_ENABLED, upnpEnabled_);
 }
 
 std::map<std::string, std::string> Account::getAccountDetails() const
@@ -260,6 +266,7 @@ std::map<std::string, std::string> Account::getAccountDetails() const
     a[Conf::CONFIG_ACCOUNT_AUTOANSWER] = autoAnswerEnabled_ ? TRUE_STR : FALSE_STR;
     a[Conf::CONFIG_RINGTONE_ENABLED] = ringtoneEnabled_ ? TRUE_STR : FALSE_STR;
     a[Conf::CONFIG_RINGTONE_PATH] = ringtonePath_;
+    a[Conf::CONFIG_UPNP_ENABLED] = upnpEnabled_ ? TRUE_STR : FALSE_STR;
 
     return a;
 }
@@ -459,26 +466,41 @@ Account::parseBool(const std::map<std::string, std::string> &details, const char
 
 #undef find_iter
 
-void
-Account::setUseUPnP(bool useUPnP)
+/**
+ * Checks whether the upnp settings is enabled in the account.
+ * If so, tries to get a controller with a valid IGD.
+ * If not, destroys the controller.
+ *
+ * Returns whether or not there is a controller with a valid IGD to use.
+ */
+bool
+Account::checkUPnP()
 {
     std::unique_lock<std::mutex> lk(upnp_mtx);
 
-    if (useUPnP == static_cast<bool>(upnp_))
-        return;
+    if (upnpEnabled_ != (bool)upnp_) {
+        if (upnpEnabled_){
+            upnp_.reset(new upnp::Controller());
+            if (upnp_->hasValidIGD())
+                upnpIp_ = upnp_->getExternalIP();
+        } else {
+            upnp_.reset();
+            upnpIp_ = IpAddr{};
+        }
+    }
 
-    if (useUPnP){
-        upnp_.reset(new upnp::Controller());
-        upnpIp_ = upnp_->getExternalIP();
-    } else
-        upnp_.reset();
+    return upnp_ and upnp_->hasValidIGD();
 }
 
+/**
+ * Returns whether or not the upnp controller has a valid IGD
+ * with which to make port mappings
+ */
 bool
 Account::getUseUPnP() const
 {
     std::unique_lock<std::mutex> lk(upnp_mtx);
-    return static_cast<bool>(upnp_);
+    return upnp_ and upnp_->hasValidIGD();
 }
 
 } // namespace ring
diff --git a/daemon/src/account.h b/daemon/src/account.h
index 15590e4762a482c55b8a2eff8593f73406b36ada..9f5075ff203caeba9f003169f0819e572a9ac4a3 100644
--- a/daemon/src/account.h
+++ b/daemon/src/account.h
@@ -255,12 +255,6 @@ class Account : public Serializable, public std::enable_shared_from_this<Account
         static const char * const VIDEO_CODEC_BITRATE;
 
         /**
-         * Set whether or not to use UPnP
-         */
-        void setUseUPnP(bool useUPnP);
-
-        /**
-         * Get whether UPnP is used.
          * @return bool Flag which determines if UPnP is used or not.
          */
         bool getUseUPnP() const;
@@ -313,6 +307,7 @@ class Account : public Serializable, public std::enable_shared_from_this<Account
         static const char * const HAS_CUSTOM_USER_AGENT_KEY;
         static const char * const DEFAULT_USER_AGENT;
         static const char * const PRESENCE_MODULE_ENABLED_KEY;
+        static const char * const UPNP_ENABLED_KEY;
 
         static std::string mapStateNumberToString(RegistrationState state);
 
@@ -414,6 +409,23 @@ class Account : public Serializable, public std::enable_shared_from_this<Account
         IpAddr upnpIp_ {};
         std::unique_ptr<ring::upnp::Controller> upnp_;
         mutable std::mutex upnp_mtx {};
+
+        /**
+         * Whether or not UPnP is enabled for this account
+         * Note that this is only used to store the account setting,
+         * getUseUPnP() should be used to check if UPnP is being use
+         * ie: if the UPnP controller has been initialized
+         */
+        bool upnpEnabled_;
+
+        /**
+         * Checks whether the upnp settings is enabled in the account.
+         * If so, tries to get a controller with a valid IGD.
+         * If not, destroys the controller.
+         *
+         * Returns whether or not there is a controller with a valid IGD to use.
+         */
+        bool checkUPnP();
 };
 
 } // namespace ring
diff --git a/daemon/src/account_schema.h b/daemon/src/account_schema.h
index 4c2607809ca2a4c8ebc0e3f0ee322c52df9a5d20..495b617073e9b1a517a0ab4b189134d04297dea5 100644
--- a/daemon/src/account_schema.h
+++ b/daemon/src/account_schema.h
@@ -74,6 +74,7 @@ static const char *const CONFIG_PUBLISHED_SAMEAS_LOCAL          = "Account.publi
 static const char *const CONFIG_LOCAL_PORT                      = "Account.localPort";
 static const char *const CONFIG_PUBLISHED_PORT                  = "Account.publishedPort";
 static const char *const CONFIG_PUBLISHED_ADDRESS               = "Account.publishedAddress";
+static const char *const CONFIG_UPNP_ENABLED                    = "Account.upnpEnabled";
 
 // SIP specific parameters
 static const char *const CONFIG_STUN_SERVER                     = "STUN.server";
diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp
index cb4586f80b87b1571cadc688d71de86bf976457f..c9d01821955678bfb31e0d3df23b28bbaf4d73bd 100644
--- a/daemon/src/managerimpl.cpp
+++ b/daemon/src/managerimpl.cpp
@@ -243,10 +243,10 @@ ManagerImpl::init(const std::string &config_file)
 
     history_.load(preferences.getHistoryLimit());
 
-    if (preferences.getUseUPnP()) {
-        RING_DBG("Remove any old UPnP mappings for RING mapped to this IP");
-        upnp::Controller().removeMappingsByLocalIPAndDescription();
-    }
+    /* TODO: Is this necessary? This will require looking for a UPnP enabled IGD at each start
+     * of the daemon... */
+    RING_DBG("Remove any old UPnP mappings for RING mapped to this IP");
+    upnp::Controller().removeMappingsByLocalIPAndDescription();
 
     registerAccounts();
 }
@@ -295,10 +295,9 @@ ManagerImpl::finish()
         RING_ERR("%s", err.what());
     }
 
-    if (preferences.getUseUPnP()) {
-        RING_DBG("Remove any remaning ports mapped to this client for RING");
-        upnp::Controller().removeMappingsByLocalIPAndDescription();
-    }
+
+    RING_DBG("Remove any remaning ports mapped to this client for RING");
+    upnp::Controller().removeMappingsByLocalIPAndDescription();
 }
 
 bool
@@ -2407,7 +2406,6 @@ ManagerImpl::setAccountDetails(const std::string& accountID,
         saveConfig();
 
         if (account->isEnabled()) {
-            account->setUseUPnP(preferences.getUseUPnP());
             account->doRegister();
         } else
             account->doUnregister();
@@ -2454,8 +2452,6 @@ ManagerImpl::addAccount(const std::map<std::string, std::string>& details)
 
     preferences.addAccount(newAccountID);
 
-    newAccount->setUseUPnP(preferences.getUseUPnP());
-
     newAccount->doRegister();
 
     saveConfig();
@@ -2715,7 +2711,6 @@ ManagerImpl::registerAccounts()
         a->loadConfig();
 
         if (a->isEnabled()) {
-            a->setUseUPnP(preferences.getUseUPnP());
             a->doRegister();
         }
     }
@@ -2743,7 +2738,6 @@ ManagerImpl::sendRegister(const std::string& accountID, bool enable)
     Manager::instance().saveConfig();
 
     if (acc->isEnabled()) {
-        acc->setUseUPnP(preferences.getUseUPnP());
         acc->doRegister();
     } else
         acc->doUnregister();
diff --git a/daemon/src/preferences.cpp b/daemon/src/preferences.cpp
index 57c81f6ca0cb6dd0dc2dec7628fa6781a64d53f4..504c34fbc3e7c22631ebf3652f7473b70bc29bea 100644
--- a/daemon/src/preferences.cpp
+++ b/daemon/src/preferences.cpp
@@ -77,7 +77,6 @@ static const char * const ZONE_TONE_CHOICE_KEY = "zoneToneChoice";
 static const char * const PORT_NUM_KEY = "portNum";
 static const char * const SEARCH_BAR_DISPLAY_KEY = "searchBarDisplay";
 static const char * const MD5_HASH_KEY = "md5Hash";
-static const char * const USE_UPNP = "useUPnP";
 
 // voip preferences
 constexpr const char * const VoipPreference::CONFIG_LABEL;
@@ -138,7 +137,6 @@ Preferences::Preferences() :
     , portNum_(5060)
     , searchBarDisplay_(true)
     , md5Hash_(false)
-    , useUPnP_(false)
 {}
 
 void Preferences::verifyAccountOrder(const std::vector<std::string> &accountIDs)
@@ -197,7 +195,6 @@ void Preferences::serialize(YAML::Emitter &out)
     out << YAML::Key << REGISTRATION_EXPIRE_KEY << YAML::Value << registrationExpire_;
     out << YAML::Key << SEARCH_BAR_DISPLAY_KEY << YAML::Value << searchBarDisplay_;
     out << YAML::Key << ZONE_TONE_CHOICE_KEY << YAML::Value << zoneToneChoice_;
-    out << YAML::Key << USE_UPNP << YAML::Value << useUPnP_;
     out << YAML::EndMap;
 }
 
@@ -213,7 +210,6 @@ void Preferences::unserialize(const YAML::Node &in)
     parseValue(node, PORT_NUM_KEY, portNum_);
     parseValue(node, SEARCH_BAR_DISPLAY_KEY, searchBarDisplay_);
     parseValue(node, MD5_HASH_KEY, md5Hash_);
-    parseValue(node, USE_UPNP, useUPnP_);
 }
 
 VoipPreference::VoipPreference() :
diff --git a/daemon/src/preferences.h b/daemon/src/preferences.h
index f601e7c616afd012122e600db6180983c1c3aca2..54887d326565a5c89f54106e3ae45e11215dd549 100644
--- a/daemon/src/preferences.h
+++ b/daemon/src/preferences.h
@@ -126,13 +126,6 @@ class Preferences : public Serializable {
             md5Hash_ = md5;
         }
 
-        bool getUseUPnP() const {
-            return useUPnP_;
-        }
-        void setUseUPnP(bool upnp) {
-            useUPnP_ = upnp;
-        }
-
     private:
         std::string accountOrder_;
         int historyLimit_;
@@ -142,7 +135,6 @@ class Preferences : public Serializable {
         int portNum_;
         bool searchBarDisplay_;
         bool md5Hash_;
-        bool useUPnP_;
         constexpr static const char * const CONFIG_LABEL = "preferences";
 };
 
diff --git a/daemon/src/ringdht/ringaccount.cpp b/daemon/src/ringdht/ringaccount.cpp
index f52e29856d261293b271d21e69c44a487b2acced..c07cd925cd38355e006cffe9cf1a60a80825dfa0 100644
--- a/daemon/src/ringdht/ringaccount.cpp
+++ b/daemon/src/ringdht/ringaccount.cpp
@@ -603,7 +603,9 @@ void RingAccount::doRegister()
         return;
     }
 
-    if (not mapPortUPnP())
+    /* check UPnP to see if the account setting is enabled and try to get a
+     * UPnP controller; if this succeeds then try to map the account port */
+    if (not (checkUPnP() and mapPortUPnP()) )
         RING_WARN("Could not successfully map DHT port with UPnP, continuing with account registration anyways.");
 
     try {
diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp
index 2cbd92b08af26588e2b138da54a1568bb9a4e147..125c2c173414024ce1f15e575ab0a955015b2f24 100644
--- a/daemon/src/sip/sipaccount.cpp
+++ b/daemon/src/sip/sipaccount.cpp
@@ -744,7 +744,9 @@ void SIPAccount::doRegister()
 
     RING_DBG("doRegister %s", hostname_.c_str());
 
-    if (not mapPortUPnP())
+    /* check UPnP to see if the account setting is enabled and try to get a
+     * UPnP controller; if this succeeds then try to map the account port */
+    if (not (checkUPnP() and mapPortUPnP()) )
         RING_WARN("Could not successfully map SIP port with UPnP, continuing with account registration anyways.");
 
     if (hostname_.empty() || isIP2IP()) {
diff --git a/daemon/src/upnp/upnp.cpp b/daemon/src/upnp/upnp.cpp
index ac2ff91c48abbb946f2f4ca875330fb38f639b57..70e246e4923b0eb8954a4c35a09cb39539285be4 100644
--- a/daemon/src/upnp/upnp.cpp
+++ b/daemon/src/upnp/upnp.cpp
@@ -88,7 +88,6 @@ IGD& IGD::operator=(IGD&& other)
 IGD::~IGD()
 {
     /* free the URLs */
-    RING_WARN("UPnP : deleting IGD");
     FreeUPNPUrls(&urls_);
 }
 
@@ -145,6 +144,19 @@ Controller::~Controller()
     removeMappings();
 }
 
+/**
+ * Return whether or not this controller has a valid IGD,
+ * if 'flase' then all requests will fail
+ */
+bool
+Controller::hasValidIGD()
+{
+#if HAVE_UPNP
+    return not defaultIGD_->isEmpty();
+#endif
+    return false;
+}
+
 /**
  * tries to add mapping
  */
diff --git a/daemon/src/upnp/upnp.h b/daemon/src/upnp/upnp.h
index 86902edbf3c934ad27f457db9cce032d3022d9ee..dfd9d9259dcff5fa6e6d1f877b1450e36318ac93 100644
--- a/daemon/src/upnp/upnp.h
+++ b/daemon/src/upnp/upnp.h
@@ -162,6 +162,12 @@ public:
     /* destructor */
     ~Controller();
 
+    /**
+     * Return whether or not this controller has a valid IGD,
+     * if 'flase' then all requests will fail
+     */
+    bool hasValidIGD();
+
     /**
      * tries to add mapping from and to the port_desired
      * if unique == true, makes sure the client is not using this port already