diff --git a/pyghmi/ipmi/private/serversession.py b/pyghmi/ipmi/private/serversession.py
index ee8cea69..06bcbddb 100644
--- a/pyghmi/ipmi/private/serversession.py
+++ b/pyghmi/ipmi/private/serversession.py
@@ -78,7 +78,10 @@ class ServerSession(ipmisession.Session):
         self.sockaddr = clientaddr
         self.pendingpayloads = collections.deque([])
         self.pktqueue = collections.deque([])
-        ipmisession.Session.bmc_handlers[clientaddr] = self
+        if clientaddr not in ipmisession.Session.bmc_handlers:
+            ipmisession.Session.bmc_handlers[clientaddr] = {bmc.port: self}
+        else:
+            ipmisession.Session.bmc_handlers[clientaddr][bmc.port] = self
         response = self.create_open_session_response(bytearray(request))
         self.send_payload(response,
                           constants.payload_types['rmcpplusopenresponse'],
@@ -267,10 +270,11 @@ class IpmiServer(object):
                                    authstatus, chancap, *oemdata)
         self.kg = None
         self.timeout = 60
+        self.port = port
         addrinfo = socket.getaddrinfo(address, port, 0,
                                       socket.SOCK_DGRAM)[0]
         self.serversocket = ipmisession.Session._assignsocket(addrinfo)
-        ipmisession.Session.bmc_handlers[self.serversocket] = self
+        ipmisession.Session.bmc_handlers[self.serversocket] = {0: self}
 
     def send_auth_cap(self, myaddr, mylun, clientaddr, clientlun, clientseq,
                       sockaddr):
diff --git a/pyghmi/ipmi/private/session.py b/pyghmi/ipmi/private/session.py
index 721fdacc..9544bb3d 100644
--- a/pyghmi/ipmi/private/session.py
+++ b/pyghmi/ipmi/private/session.py
@@ -196,16 +196,18 @@ def _io_graball(mysockets, iowaiters):
             # into the select
             if len(rdata[0]) < 4:
                 continue
+            myport = mysocket.getsockname()[1]
             rdata = rdata + (mysocket,)
             relsession = None
-            if rdata[1] in Session.bmc_handlers:
+            if (rdata[1] in Session.bmc_handlers and
+                    myport in Session.bmc_handlers[rdata[1]]):
                 # session data
                 rdata = rdata + (True,)
-                relsession = Session.bmc_handlers[rdata[1]]
+                relsession = Session.bmc_handlers[rdata[1]][myport]
             elif rdata[2] in Session.bmc_handlers:
                 # pyghmi is the bmc, and we have sessionless data
                 rdata = rdata + (False,)
-                relsession = Session.bmc_handlers[rdata[2]]
+                relsession = Session.bmc_handlers[rdata[2]][0]
             if relsession is not None:
                 relsession.pktqueue.append(rdata)
                 sessionqueue.append(relsession)
@@ -302,12 +304,13 @@ class Session(object):
     @classmethod
     def _cleanup(cls):
         for sesskey in list(cls.bmc_handlers):
-            session = cls.bmc_handlers[sesskey]
-            session.cleaningup = True
-            session.logout()
+            for portent in list(cls.bmc_handlers[sesskey]):
+                session = cls.bmc_handlers[sesskey][portent]
+                session.cleaningup = True
+                session.logout()
 
     @classmethod
-    def _assignsocket(cls, server=None):
+    def _assignsocket(cls, server=None, forbiddensockets=()):
         global iothread
         global iothreadready
         global iosockets
@@ -321,9 +324,15 @@ class Session(object):
         if server is None:
             sorted_candidates = sorted(dictitems(cls.socketpool),
                                        key=operator.itemgetter(1))
-        if sorted_candidates and sorted_candidates[0][1] < MAX_BMCS_PER_SOCKET:
-            cls.socketpool[sorted_candidates[0][0]] += 1
-            return sorted_candidates[0][0]
+        if sorted_candidates is None:
+            sorted_candidates = []
+        for candidate in sorted_candidates:
+            if candidate[1] >= MAX_BMCS_PER_SOCKET:
+                break
+            if candidate[0] in forbiddensockets:
+                continue
+            cls.socketpool[candidate[0]] += 1
+            return candidate[0]
         # we need a new socket
         if server:
             # Regardless of whether ipv6 is supported or not, we
@@ -403,6 +412,7 @@ class Session(object):
                 kg=None,
                 onlogon=None):
         trueself = None
+        forbidsock = []
         for res in socket.getaddrinfo(bmc, port, 0, socket.SOCK_DGRAM):
             sockaddr = res[4]
             if ipv6support and res[0] == socket.AF_INET:
@@ -410,17 +420,29 @@ class Session(object):
                 newhost = '::ffff:' + sockaddr[0]
                 sockaddr = (newhost, sockaddr[1], 0, 0)
             if sockaddr in cls.bmc_handlers:
-                self = cls.bmc_handlers[sockaddr]
-                if (self.bmc == bmc and self.userid == userid and
-                        self.password == password and self.kgo == kg and
-                        (self.logged or self.logging) and
-                        cls._is_session_valid(self)):
-                    trueself = self
-                else:
-                    del cls.bmc_handlers[sockaddr]
+                for portself in list(dictitems(cls.bmc_handlers[sockaddr])):
+                    self = portself[1]
+                    if not ((self.logged or self.logging) and
+                            cls._is_session_valid(self)):
+                        # we have encountered a leftover broken session
+                        del cls.bmc_handlers[sockaddr][portself[0]]
+                        continue
+                    if (self.bmc == bmc and self.userid == userid and
+                            self.password == password and self.kgo == kg):
+                        trueself = self
+                        break
+                    # ok, the candidate seems to be working, but does not match
+                    # will need to allow creation of a new session, but
+                    # must forbid use of this socket so that the socket
+                    # share routing code does not get confused.
+                    # in principle, should be able to distinguish by session
+                    # id, however it's easier this way
+                    forbidsock.append(self.socket)
             if trueself:
                 return trueself
-            return object.__new__(cls)
+            self = object.__new__(cls)
+            self.forbidsock = forbidsock
+            return self
 
     def __init__(self,
                  bmc,
@@ -486,7 +508,7 @@ class Session(object):
         if self.__class__.socketchecking is None:
             self.__class__.socketchecking = threading.Lock()
         with self.socketchecking:
-            self.socket = self._assignsocket()
+            self.socket = self._assignsocket(forbiddensockets=self.forbidsock)
         self.login()
         if not self.async:
             while self.logging:
@@ -522,9 +544,13 @@ class Session(object):
                 # since this session is broken, remove it from the handler list
                 # This allows constructor to create a new, functional object to
                 # replace this one
+                myport = self.socket.getsockname()[1]
                 for sockaddr in self.allsockaddrs:
-                    if sockaddr in Session.bmc_handlers:
-                        del Session.bmc_handlers[sockaddr]
+                    if (sockaddr in Session.bmc_handlers and
+                            myport in Session.bmc_hansdlers[sockaddr]):
+                        del Session.bmc_handlers[sockaddr][myport]
+                        if Session.bmc_handlers[sockaddr] == {}:
+                            del Session.bmc_handlers[sockaddr]
         elif not self.broken:
             self.broken = True
             self.socketpool[self.socket] -= 1
@@ -1200,23 +1226,14 @@ class Session(object):
             pkt[0] = bytearray(pkt[0])
             if not (pkt[0][0] == 6 and pkt[0][2:4] == b'\xff\x07'):
                 continue
+            # this should be in specific context, no need to check port
+            # since recvfrom result was already routed to this object
+            # specifically
             if pkt[1] in self.bmc_handlers:
                 self._handle_ipmi_packet(pkt[0], sockaddr=pkt[1], qent=pkt)
             elif pkt[2] in self.bmc_handlers:
                 self.sessionless_data(pkt[0], pkt[1])
 
-    @classmethod
-    def _route_ipmiresponse(cls, sockaddr, data, mysocket):
-        if not (data[0] == '\x06' and data[2:4] == '\xff\x07'):  # not ipmi
-            return
-        try:
-            cls.bmc_handlers[sockaddr]._handle_ipmi_packet(data,
-                                                           sockaddr=sockaddr)
-        except KeyError:
-            # check if we have a server attached to the target socket
-            if mysocket in cls.bmc_handlers:
-                cls.bmc_handlers[mysocket].sessionless_data(data, sockaddr)
-
     def _handle_ipmi_packet(self, data, sockaddr=None, qent=None):
         if self.sockaddr is None and sockaddr is not None:
             self.sockaddr = sockaddr
@@ -1235,7 +1252,7 @@ class Session(object):
                 # still active UDP source port.  Clear ourselves out and punt
                 # to IpmiServer
                 del Session.bmc_handlers[sockaddr]
-                iserver = Session.bmc_handlers[qent[2]]
+                iserver = Session.bmc_handlers[qent[2]][0]
                 iserver.pktqueue.append(qent)
                 iserver.process_pktqueue()
                 return
@@ -1657,6 +1674,7 @@ class Session(object):
             # he have not yet picked a working sockaddr for this connection,
             # try all the candidates that getaddrinfo provides
             self.allsockaddrs = []
+            myport = self.socket.getsockname()[1]
             try:
                 for res in socket.getaddrinfo(self.bmc,
                                               self.port,
@@ -1668,7 +1686,9 @@ class Session(object):
                         newhost = '::ffff:' + sockaddr[0]
                         sockaddr = (newhost, sockaddr[1], 0, 0)
                     self.allsockaddrs.append(sockaddr)
-                    Session.bmc_handlers[sockaddr] = self
+                    if sockaddr not in Session.bmc_handlers:
+                        Session.bmc_handlers[sockaddr] = {}
+                    Session.bmc_handlers[sockaddr][myport] = self
                     _io_sendto(self.socket, self.netpacket, sockaddr)
             except socket.gaierror:
                 raise exc.IpmiException(