diff --git a/packages/toolkit/src/query/react/buildHooks.ts b/packages/toolkit/src/query/react/buildHooks.ts
--- a/packages/toolkit/src/query/react/buildHooks.ts
+++ b/packages/toolkit/src/query/react/buildHooks.ts
@@ -905,16 +905,17 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
       const { endpointName } = lastResult
       const endpointDefinition = context.endpointDefinitions[endpointName]
       if (
+        queryArgs !== skipToken &&
         serializeQueryArgs({
           queryArgs: lastResult.originalArgs,
           endpointDefinition,
           endpointName,
         }) ===
-        serializeQueryArgs({
-          queryArgs,
-          endpointDefinition,
-          endpointName,
-        })
+          serializeQueryArgs({
+            queryArgs,
+            endpointDefinition,
+            endpointName,
+          })
       )
         lastResult = undefined
     }

diff --git a/packages/toolkit/src/query/tests/buildHooks.test.tsx b/packages/toolkit/src/query/tests/buildHooks.test.tsx
--- a/packages/toolkit/src/query/tests/buildHooks.test.tsx
+++ b/packages/toolkit/src/query/tests/buildHooks.test.tsx
@@ -3077,6 +3077,48 @@ describe('skip behavior', () => {
     expect(getSubscriptionCount('getUser(1)')).toBe(0)
   })
 
+  test('skipToken does not break serializeQueryArgs', async () => {
+    const { result, rerender } = renderHook(
+      ([arg, options]: Parameters<
+        typeof api.endpoints.queryWithDeepArg.useQuery
+      >) => api.endpoints.queryWithDeepArg.useQuery(arg, options),
+      {
+        wrapper: storeRef.wrapper,
+        initialProps: [skipToken],
+      },
+    )
+
+    expect(result.current).toEqual(uninitialized)
+    await waitMs(1)
+
+    expect(getSubscriptionCount('nestedValue')).toBe(0)
+    // also no subscription on `getUser(skipToken)` or similar:
+    expect(getSubscriptions()).toEqual({})
+
+    rerender([{ param: { nested: 'nestedValue' } }])
+
+    await act(async () => {
+      await waitForFakeTimer(150)
+    })
+
+    expect(result.current).toMatchObject({ status: QueryStatus.fulfilled })
+    await waitMs(1)
+
+    expect(getSubscriptionCount('nestedValue')).toBe(1)
+    expect(getSubscriptions()).not.toEqual({})
+
+    rerender([skipToken])
+
+    expect(result.current).toEqual({
+      ...uninitialized,
+      isSuccess: true,
+      currentData: undefined,
+      data: {},
+    })
+    await waitMs(1)
+    expect(getSubscriptionCount('nestedValue')).toBe(0)
+  })
+
   test('skipping a previously fetched query retains the existing value as `data`, but clears `currentData`', async () => {
     const { result, rerender } = renderHook(
       ([arg, options]: Parameters<typeof api.endpoints.getUser.useQuery>) =>

Add missing API ref docs for the `invalidationBehavior` option for `createApi`
We merged https://github.com/reduxjs/redux-toolkit/pull/3116 for the new `invalidationBehavior` setting in RTK 2.0, but never actually covered that in the API docs. Needs to be covered in the `createApi` options.

We do have a docblock with a description here:

https://github.com/reduxjs/redux-toolkit/blob/e848a552dec33c0c55951462c219ad00cb8d3978/packages/toolkit/src/query/createApi.ts#L154-L163

and `createApi.mdx` already uses a build-time system that can pull docblock descriptions from the code into the Markdown file:

```md
### `tagTypes`

[summary](docblock://query/createApi.ts?token=CreateApiOptions.tagTypes)

[examples](docblock://query/createApi.ts?token=CreateApiOptions.tagTypes)
```

So, we'll want to add another header section for the `invalidationBehavior` option and include the summary there, as well as possibly add more description or examples.
