diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt
index d23229232..5db01fea0 100644
--- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt
+++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt
@@ -102,6 +102,16 @@ internal open class QQAndroidBot constructor(
 
                 override fun toString(): String = "StateChangedObserver(BotOnlineEventBroadcaster)"
             },
+            StateChangedObserver("LastConnectedAddressUpdater", State.OK) {
+                components[ServerList].run {
+                    lastConnectedIP = getLastPolledIP()
+                }
+            },
+            StateChangedObserver("LastDisconnectedAddressUpdater", State.CLOSED) {
+                components[ServerList].run {
+                    lastDisconnectedIP = lastConnectedIP
+                }
+            },
             StateChangedObserver("BotOfflineEventBroadcaster", State.OK, State.CLOSED) { new ->
                 // logging performed by BotOfflineEventMonitor
                 val cause = new.getCause()
diff --git a/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt b/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt
index acae9edec..2f8791432 100644
--- a/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt
+++ b/mirai-core/src/commonMain/kotlin/network/components/ServerList.kt
@@ -58,6 +58,22 @@ internal interface ServerList {
      */
     fun refresh()
 
+
+    /**
+     * Last disconnected ip
+     */
+    var lastDisconnectedIP: String
+
+    /**
+     * Last connected ip
+     */
+    var lastConnectedIP: String
+
+    /**
+     * Get last poll ip
+     */
+    fun getLastPolledIP(): String
+
     /**
      * [Poll][Queue.poll] from current address list. Returns `null` if current address list is empty.
      */
@@ -100,6 +116,9 @@ internal class ServerListImpl(
     @Volatile
     private var current: Queue<ServerAddress> = ArrayDeque(initial)
 
+    @Volatile
+    private var lastPolledAddress: ServerAddress? = null
+
     @Synchronized
     override fun setPreferred(list: Collection<ServerAddress>) {
         logger.info { "Server list: ${list.joinToString()}." }
@@ -121,12 +140,19 @@ internal class ServerListImpl(
         }
     }
 
+    override var lastDisconnectedIP: String = ""
+    override var lastConnectedIP: String = ""
+
+    override fun getLastPolledIP(): String = lastPolledAddress?.host ?: ""
+
     /**
      * [Poll][Queue.poll] from current address list. Returns `null` if current address list is empty.
      */
     @Synchronized
     override fun pollCurrent(): ServerAddress? {
-        return current.poll()
+        return current.poll()?.also { address ->
+            lastPolledAddress = address
+        }
     }
 
     /**
@@ -135,10 +161,12 @@ internal class ServerListImpl(
     @Synchronized
     override fun pollAny(): ServerAddress {
         if (current.isEmpty()) refresh()
-        return current.remove()
+        return current.remove().also { address ->
+            lastPolledAddress = address
+        }
     }
 
     override fun toString(): String {
         return "ServerListImpl(current.size=${current.size})"
     }
-}
\ No newline at end of file
+}
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt
index 2d9a7d620..585b3dd59 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt
@@ -30,6 +30,7 @@ import net.mamoe.mirai.internal.message.contextualBugReportException
 import net.mamoe.mirai.internal.network.*
 import net.mamoe.mirai.internal.network.components.ContactCacheService
 import net.mamoe.mirai.internal.network.components.ContactUpdater
+import net.mamoe.mirai.internal.network.components.ServerList
 import net.mamoe.mirai.internal.network.impl.netty.HeartbeatFailedException
 import net.mamoe.mirai.internal.network.protocol.data.jce.*
 import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x769
@@ -39,6 +40,8 @@ import net.mamoe.mirai.internal.network.protocol.packet.*
 import net.mamoe.mirai.internal.utils.NetworkType
 import net.mamoe.mirai.internal.utils._miraiContentToString
 import net.mamoe.mirai.internal.utils.io.serialization.*
+import net.mamoe.mirai.internal.utils.toIpV4Long
+import net.mamoe.mirai.utils.BotConfiguration
 import net.mamoe.mirai.utils.currentTimeMillis
 import net.mamoe.mirai.utils.encodeToString
 import net.mamoe.mirai.utils.toReadPacket
@@ -158,16 +161,27 @@ internal class StatSvc {
             client: QQAndroidClient,
             regPushReason: RegPushReason = RegPushReason.appRegister
         ) = impl("online", client, 1L or 2 or 4, client.onlineStatus, regPushReason) {
-            client.bot.components[ContactCacheService].friendListCache?.let { friendListCache: FriendListCache ->
-                iLargeSeq = friendListCache.friendListSeq
-                //  timeStamp = friendListCache.timeStamp
+            if (client.bot.configuration.protocol == BotConfiguration.MiraiProtocol.ANDROID_PHONE) {
+                client.bot.components[ServerList].run {
+                    uOldSSOIp = lastDisconnectedIP.toIpV4Long()
+                    uNewSSOIp = lastConnectedIP.toIpV4Long()
+                }
+            } else {
+                uOldSSOIp = 0
+                uNewSSOIp = 0
             }
+            client.bot.components[ContactCacheService].friendListCache?.let { friendListCache ->
+                iLargeSeq = friendListCache.friendListSeq
+            }
+            //  timeStamp = friendListCache.timeStamp
+            strVendorName = "MIUI"
+            strVendorOSName = "?ONEPLUS A5000_23_17"
         }
 
         fun offline(
             client: QQAndroidClient,
             regPushReason: RegPushReason = RegPushReason.appRegister
-        ) = impl("offline", client, 0, OnlineStatus.OFFLINE, regPushReason)
+        ) = impl("offline", client, 1L or 2 or 4, OnlineStatus.OFFLINE, regPushReason)
 
         private fun impl(
             name: String,
@@ -221,10 +235,6 @@ internal class StatSvc {
                                 strDevName = client.device.model.encodeToString(),
                                 strDevType = client.device.model.encodeToString(),
                                 strOSVer = client.device.version.release.encodeToString(),
-                                uOldSSOIp = 0,
-                                uNewSSOIp = 0,
-                                strVendorName = "MIUI",
-                                strVendorOSName = "?ONEPLUS A5000_23_17",
                                 // register 时还需要
                                 /*
                                 var44.uNewSSOIp = field_127445;
diff --git a/mirai-core/src/commonMain/kotlin/utils/type.kt b/mirai-core/src/commonMain/kotlin/utils/type.kt
index 90b1a4f3f..77ccfe7eb 100644
--- a/mirai-core/src/commonMain/kotlin/utils/type.kt
+++ b/mirai-core/src/commonMain/kotlin/utils/type.kt
@@ -11,6 +11,9 @@ package net.mamoe.mirai.internal.utils
 
 import net.mamoe.mirai.contact.ContactOrBot
 import net.mamoe.mirai.message.data.*
+import net.mamoe.mirai.utils.toInt
+import net.mamoe.mirai.utils.toLongUnsigned
+import java.net.Inet4Address
 
 
 internal fun Int.toIpV4AddressString(): String {
@@ -27,6 +30,18 @@ internal fun Int.toIpV4AddressString(): String {
     }
 }
 
+internal fun String.toIpV4Long(): Long {
+    return if (isEmpty()) {
+        0
+    } else {
+        try {
+            Inet4Address.getByName(this).address.toInt().toLongUnsigned()
+        } catch (e: UnknownHostException) {
+            -2
+        }
+    }
+}
+
 internal fun String.chineseLength(upTo: Int): Int {
     return this.sumUpTo(upTo) {
         when (it) {
diff --git a/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt b/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt
index ec73719ae..57c6b6c4e 100644
--- a/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt
+++ b/mirai-core/src/commonTest/kotlin/network/ServerListTest.kt
@@ -27,6 +27,18 @@ internal class ServerListTest : AbstractTest() {
         assertNotNull(ServerListImpl().pollCurrent())
     }
 
+    @Test
+    fun `last poll ip is updated when polled`() {
+        val instance = ServerListImpl()
+        val old = instance.getLastPolledIP()
+        assertNotNull(old)
+        assert(old.isEmpty())
+        assertNotNull(instance.pollCurrent())
+        val new = instance.getLastPolledIP()
+        assertNotNull(new)
+        assertNotEquals(old, new)
+    }
+
     @Test
     fun `not empty for initial`() {
         assertNotNull(ServerListImpl().pollAny())
diff --git a/mirai-core/src/commonTest/kotlin/network/framework/AbstractNettyNHTestWithSelector.kt b/mirai-core/src/commonTest/kotlin/network/framework/AbstractNettyNHTestWithSelector.kt
index 2c9c0ebca..0242c7c56 100644
--- a/mirai-core/src/commonTest/kotlin/network/framework/AbstractNettyNHTestWithSelector.kt
+++ b/mirai-core/src/commonTest/kotlin/network/framework/AbstractNettyNHTestWithSelector.kt
@@ -34,7 +34,7 @@ internal abstract class AbstractNettyNHTestWithSelector : AbstractRealNetworkHan
     val channel = AbstractNettyNHTest.NettyNHTestChannel()
 
     val selector = TestSelector<TestNettyNH> {
-        object : TestNettyNH(bot, createContext(), address) {
+        object : TestNettyNH(bot, createContext(), createAddress()) {
             override suspend fun createConnection(decodePipeline: PacketDecodePipeline): Channel = channel
         }
     }
diff --git a/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt b/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt
index 417c9e1e0..65a24c005 100644
--- a/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt
+++ b/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt
@@ -132,11 +132,13 @@ internal sealed class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abstr
         return instance
     }
 
-    open fun createHandler(): NetworkHandler = factory.create(createContext(), address)
+    open fun createHandler(): NetworkHandler = factory.create(createContext(), createAddress())
     open fun createContext(): NetworkHandlerContextImpl =
         NetworkHandlerContextImpl(bot, networkLogger, bot.createNetworkLevelComponents())
 
-    val address: InetSocketAddress = InetSocketAddress.createUnresolved("localhost", 123)
+    //Use overrideComponents to avoid StackOverflowError when applying components
+    open fun createAddress(): InetSocketAddress =
+        overrideComponents[ServerList].pollAny().let { InetSocketAddress.createUnresolved(it.host, it.port) }
 
     ///////////////////////////////////////////////////////////////////////////
     // Assertions
diff --git a/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyAddressChangedTest.kt b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyAddressChangedTest.kt
new file mode 100644
index 000000000..333830ea9
--- /dev/null
+++ b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyAddressChangedTest.kt
@@ -0,0 +1,39 @@
+package net.mamoe.mirai.internal.network.impl.netty
+
+import net.mamoe.mirai.internal.network.components.ServerList
+import net.mamoe.mirai.internal.network.framework.AbstractNettyNHTest
+import net.mamoe.mirai.internal.network.framework.TestNettyNH
+import net.mamoe.mirai.internal.network.handler.NetworkHandler
+import net.mamoe.mirai.internal.test.runBlockingUnit
+import org.junit.jupiter.api.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
+
+internal class NettyAddressChangedTest : AbstractNettyNHTest() {
+    @Test
+    fun `test login ip changes`() = runBlockingUnit {
+        networkLogger.debug("before login, Assuming both ip is empty")
+        val lastConnectedIpOld = bot.components[ServerList].lastConnectedIP
+        val lastDisconnectedIpOld = bot.components[ServerList].lastDisconnectedIP
+        assert(lastConnectedIpOld.isEmpty()) { "Assuming lastConnectedIp is empty" }
+        assert(lastDisconnectedIpOld.isEmpty()) { "Assuming lastDisconnectedIp is empty" }
+
+        networkLogger.debug("Do login, Assuming lastConnectedIp is NOT empty")
+        bot.login()
+        assertState(NetworkHandler.State.OK)
+        assertNotEquals(
+            lastConnectedIpOld,
+            bot.components[ServerList].lastConnectedIP,
+            "Assuming lastConnectedIp is NOT empty"
+        )
+
+        networkLogger.debug("Offline the bot, Assuming lastConnectedIp is equals lastDisconnectedIp")
+        (bot.network as TestNettyNH).setStateClosed()
+        assertState(NetworkHandler.State.CLOSED)
+        assertEquals(
+            bot.components[ServerList].lastConnectedIP,
+            bot.components[ServerList].lastDisconnectedIP,
+            "Assuming lastConnectedIp is equals lastDisconnectedIp"
+        )
+    }
+}
diff --git a/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotNormalLoginTest.kt b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotNormalLoginTest.kt
index 8bbf05c09..09bc2af14 100644
--- a/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotNormalLoginTest.kt
+++ b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyBotNormalLoginTest.kt
@@ -26,7 +26,7 @@ import kotlin.test.assertFalse
 
 internal class NettyBotNormalLoginTest : AbstractNettyNHTest() {
     val selector = KeepAliveNetworkHandlerSelector(selectorLogger) {
-        super.factory.create(createContext(), address)
+        super.factory.create(createContext(), createAddress())
     }
 
     override fun createHandler(): NetworkHandler {