Connect to Memorystore for Redis or Valkey from a local machine

Memorystore for Redis and Memorystore for Valkey have only internal addresses in your VPC network, so a laptop can't connect to them directly. You need a host inside that network, and the free route is an SSH forward through a VM with no external IP, opened over IAP with gcloud compute ssh --tunnel-through-iap. We ran it from a Mac. A Redis instance with AUTH and in-transit encryption answered on port 6378 once redis-cli had --tls, the server CA and the AUTH string; its port 6379 timed out. A two-shard Valkey cluster answered PING through one forward, but redis-cli -c followed a MOVED redirect to a node address the Mac had no route to.

By Ostgate · Updated

Why your laptop can't connect

“Regardless of the connection mode, Memorystore for Redis always uses internal IP addresses to provision Redis instances” (Memorystore for Redis networking). The instance sits behind VPC peering, either direct peering (the default for new instances) or private services access. For Valkey, “The only networking connectivity method that you can use for Memorystore for Valkey is Private Service Connect service connectivity automation” (Memorystore for Valkey networking): a service connection policy places two endpoint addresses in one of your subnets.

Google's own route for a local machine is port forwarding through a Compute Engine VM (Connect to a Redis instance). Its example needs a VM you can reach by SSH:

gcloud compute ssh COMPUTE_VM_NAME --zone=ZONE \
    -- -N -L 6379:REDIS_INSTANCE_IP_ADDRESS:6379

With --tunnel-through-iap that VM needs no external IP.

The test

We ran this on 10 November 2026 from a Mac with gcloud 590.0.0 and redis-cli 8.10.3 (brew install redis), in europe-central2:

  • A Memorystore for Redis instance: Basic tier, 1 GB, Redis 7.2, direct peering, AUTH on, in-transit encryption SERVER_AUTHENTICATION
  • A Memorystore for Valkey instance: cluster mode, 2 shards, no replicas, node type shared-core-nano, Valkey 7.2, AUTH and TLS off
  • A bastion VM on the same network: e2-micro, Debian 12, internal IP only, OS Login, and a firewall rule for tcp:22 from 35.235.240.0/20

The output below is trimmed. Names and addresses are replaced with example ones; ports, error text and timings are as measured.

Forward a port through a VM over IAP

Pick a Linux VM on the instance's network. For Redis that is the instance's authorized network; for Valkey, the network of its service connection policy. Read the address and port first:

gcloud redis instances describe acme-cache \
    --region=europe-central2 --project=acme-dev --format=json \
  | jq -r '.host, .port, .transitEncryptionMode'
10.20.0.3
6378
SERVER_AUTHENTICATION

Then open the forward in a terminal and leave it running:

gcloud compute ssh example-bastion --tunnel-through-iap \
    --zone=europe-central2-a --project=acme-dev \
    -- -N -L 6378:10.20.0.3:6378

IAP reaches the VM's port 22 from 35.235.240.0/20, so that range needs an ingress rule (IAP firewall and IAM). Traffic from the VM to the instance is ordinary egress inside the VPC. The same -L pattern works for any private host the VM can reach (port forwarding over IAP).

Memorystore for Redis: TLS on 6378 and AUTH

With in-transit encryption you point the client at “port 6378”, and you “can only enable in-transit encryptions when you initially create your Redis instance” (Enabling in-transit encryption). The server CA comes from describe:

gcloud redis instances describe acme-cache \
    --region=europe-central2 --project=acme-dev --format=json \
  | jq -r '.serverCaCerts[].cert' > server-ca.pem

redis-cli reads the password from REDISCLI_AUTH, which keeps it off the command line. With -a it warns “Using a password with '-a' or '-u' option on the command line interface may not be safe.”

export REDISCLI_AUTH="$(gcloud redis instances get-auth-string acme-cache \
    --region=europe-central2 --project=acme-dev --format='value(authString)')"
redis-cli -h 127.0.0.1 -p 6378 --tls --cacert server-ca.pem PING

Through the forward, in this order:

$ redis-cli -h 127.0.0.1 -p 6378 --tls --cacert server-ca.pem PING
PONG
$ redis-cli … SET ostgate:proof "hello from a mac"
OK
$ redis-cli … GET ostgate:proof
hello from a mac

Without REDISCLI_AUTH the same PING returns NOAUTH Authentication required., and a wrong password returns AUTH failed: WRONGPASS invalid username-password pair or user is disabled.. Google notes that “AUTH string credentials are not confidential when transmitted” (Manage Redis AUTH), which is why AUTH comes with TLS here.

An instance without in-transit encryption takes plain redis-cli -p 6379 through a -L 6379:…:6379 forward. Google's TLS example puts Stunnel on the VM for clients that can't do TLS. The redis-cli we used does TLS itself, so the forward and the client on your Mac were enough.

TLS pitfalls through a forward

Each mistake has its own error. Against the encrypted instance:

# the forward points at 6379
$ redis-cli -h 127.0.0.1 -p 6379 PING
Error: Connection reset by peer
# 130.2 s later; the ssh terminal shows
channel 4: open failed: connect failed: Connection timed out

# 6378 without --tls
$ redis-cli -h 127.0.0.1 -p 6378 PING
Error: Server closed the connection

# --tls without the CA
$ redis-cli -h 127.0.0.1 -p 6378 --tls PING
Could not connect to Redis at 127.0.0.1:6378: SSL_connect failed: certificate verify failed

The first one is the connect failed: Connection timed out from the Stack Overflow question about failing Memorystore port forwarding, whose accepted answer found the instance on 6378. The server still lists a TCP listener on 6379 in INFO server, but the network drops connections to it.

The server certificate names the instance's IP and nothing else:

X509v3 Subject Alternative Name:
    DNS:10.20.0.3, IP Address:10.20.0.3

Through a forward your client connects to 127.0.0.1. redis-cli checks the chain and not the name, so it works. redis-py 8.1.0 checks the name by default:

redis.Redis(host="127.0.0.1", port=6378, ssl=True, ssl_ca_certs="server-ca.pem", password=…)
  → certificate verify failed: IP address mismatch, certificate is not valid for '127.0.0.1'
redis.Redis(…, ssl_check_hostname=False)
  → PING True

ssl_check_hostname=False still verifies the chain against the Memorystore CA. If your client lets you set the name to verify, give it the instance's IP. The certificate also changes: “Server-side certificate rotation occurs every 180 days causing a transient connection drop of a few seconds” (In-transit encryption).

Memorystore for Valkey: discovery endpoint

Creating a Valkey instance needs a service connection policy for the network, region and the gcp-memorystore service class. Ours used the bastion's subnet, and the instance got two addresses there:

gcloud memorystore instances describe acme-valkey \
    --location=europe-central2 --project=acme-dev --format=json \
  | jq -c '(.discoveryEndpoints[] | {address, port}),
           [.pscAutoConnections[].ipAddress]'
{"address":"10.30.0.4","port":6379}
["10.30.0.4","10.30.0.5"]

Clients start at the discovery endpoint, and each node uses “a port in the 11000-to-13047 range” (Memorystore for Valkey networking). The second address is the data endpoint, which Google says is “reserved for Memorystore for Valkey to use to connect your client to nodes in the instance. Therefore, don't connect to this endpoint directly” (Connect to a Valkey instance). The cluster's topology points clients at it all the same:

gcloud compute ssh example-bastion --tunnel-through-iap \
    --zone=europe-central2-a --project=acme-dev \
    -- -N -L 6380:10.30.0.4:6379
$ redis-cli -h 127.0.0.1 -p 6380 PING
PONG
$ redis-cli -h 127.0.0.1 -p 6380 CLUSTER NODES
e340d018… 10.30.0.5:11002@16379 master … 0-8191
f11f85b4… 10.30.0.5:11004@16379 myself,master … 8192-16383

Both nodes sit on the data endpoint's address, each on its own port.

Cluster mode and MOVED through one forward

The discovery endpoint hands each new connection to one of the nodes. The CLUSTER NODES above came from the node on 11004 (myself); the next connection's CLUSTER MYID came from the node on 11002. So without -c the same command works or fails depending on where it lands:

$ redis-cli -h 127.0.0.1 -p 6380 SET a 1
OK
$ redis-cli -h 127.0.0.1 -p 6380 SET b 1
MOVED 3300 10.30.0.5:11002

Six SETs gave four OK and two MOVED. With -c, which Google's Valkey docs call “cluster support mode”, redis-cli follows the redirect to 10.30.0.5:11002. Your Mac has no route to that address:

$ redis-cli -c -h 127.0.0.1 -p 6380 SET b 2
Could not connect to Redis at 10.30.0.5:11002: setsockopt(TCP_NODELAY): Invalid argument

It took 75.1 s each time, and four of six tries failed this way. The TCP_NODELAY text is misleading: the connection timed out. A cluster client in a program fails the same way: redis-py's RedisCluster gave up with Timeout connecting to server after 30.1 s.

What worked was forwarding the node ports as well and telling the client to swap the node address for 127.0.0.1:

gcloud compute ssh example-bastion --tunnel-through-iap \
    --zone=europe-central2-a --project=acme-dev \
    -- -N -L 6380:10.30.0.4:6379 \
    -L 11002:10.30.0.5:11002 -L 11004:10.30.0.5:11004
from redis.cluster import RedisCluster

remap = lambda hp: ("127.0.0.1", hp[1])
rc = RedisCluster(host="127.0.0.1", port=6380,
                  address_remap=remap)
rc.set("b", "3")
print(rc.get("b"))

That read and wrote all six keys in 0.8 s, with the nodes listed as 127.0.0.1:11002 and 127.0.0.1:11004. Read your own node ports from CLUSTER NODES. redis-cli has no such remapping, but redis-cli -p 11002 without -c works for the keys that node owns. Google also documents Valkey instances with cluster mode disabled, reached through a primary endpoint without -c; we didn't test one.

Redis and Valkey side by side

Memorystore for Redis (Basic)Memorystore for Valkey (cluster mode)
NetworkVPC peering (direct peering here)Private Service Connect, two addresses in your subnet
Before creatingNothing for direct peering; Google added the peering itselfA service connection policy, gcp-memorystore class
Address you forward tohost, port 6378 with TLS or 6379 withoutDiscovery endpoint on 6379, plus each node port for cluster clients
One -L forward is enoughYesFor PING and keys on the node you land on
RedirectsNoneMOVED to a node address in your VPC
After deleting the instanceThe redis-peer-… peering stayed on the network until we deleted itThe two endpoint addresses went with it; the service connection policy stayed until we deleted it
Auth and TLSAUTH string, TLS with the instance's CAOff in our test

How Ostgate does it

Ostgate is a native macOS app that opens IAP connections itself, with no gcloud on your Mac. Its forward profiles (Connections › Forwards › New Forward Profile…) reach anything a chosen VM can see, such as an internal load balancer or a private database, several ports at once over one SSH session. For Memorystore that VM is the bastion, and one profile can carry the Redis port and a Valkey cluster's discovery and node ports together.

  • A profile can manage /etc/hosts aliases while it runs. macOS asks for an administrator's password to write them; with the Ostgate port helper installed, an administrator's aliases need none.
  • Access decides which programs on your Mac may use a forward: Ostgate only, My processes (any app running as your macOS user, such as redis-cli) or, after you confirm it, Any local process.
  • Forwards keep running when you close the window, reconnect by themselves after a network drop and are listed under Connections and in the menu bar.

The forward carries TCP, so the CA, the AUTH string and the cluster client settings above stay in your client. Setup is in the tunnels and forwards docs.

Symptoms and causes

You seeCauseFix
SSH prints connect failed: Connection timed out, the client Connection reset by peer Forward to 6379 on an instance with in-transit encryption, or a VM on another network Read port with describe; use 6378 and a VM on the authorized network
Error: Server closed the connection on 6378 Client without TLS --tls and --cacert
SSL_connect failed: certificate verify failed The Memorystore server CA is missing Save serverCaCerts from describe and pass it
IP address mismatch for 127.0.0.1 The certificate names only the instance's IP Turn off the name check, keep chain verification
NOAUTH Authentication required. AUTH is on REDISCLI_AUTH from get-auth-string
MOVED 3300 10.30.0.5:11002 on some keys only Valkey cluster mode; the key lives on another shard Forward the node ports and remap addresses
redis-cli -c hangs, then setsockopt(TCP_NODELAY): Invalid argument The redirect points at a private node address the Mac can't reach A cluster client with address remapping, or one node port without -c

Questions

Is there something like Cloud SQL Proxy for Memorystore?

Not in the Memorystore docs we read. Google's route from a local machine is port forwarding through a Compute Engine VM on the instance's network. The VM doesn't need an external IP: gcloud compute ssh with --tunnel-through-iap reaches it over IAP, as long as a firewall rule allows tcp:22 from 35.235.240.0/20. For Redis with in-transit encryption, forward port 6378; for Valkey, forward the discovery endpoint on 6379.

Why does port forwarding to Memorystore fail with channel 2: open failed: connect failed: Connection timed out?

The VM could not open the connection to the instance's IP and port. One cause we reproduced: the Redis instance has in-transit encryption, so it serves clients on 6378, and the forward pointed at 6379. SSH logged connect failed: Connection timed out and redis-cli printed Connection reset by peer after 130 seconds. Check the port with gcloud redis instances describe. The other cause Google's docs point to is a VM outside the instance's authorized network.

Do I need a VM with an external IP to reach Memorystore from my laptop?

No. The forward runs over IAP, so the VM needs an internal IP on the instance's network, SSH access for your account and a firewall rule for tcp:22 from 35.235.240.0/20. Our bastion was an e2-micro with no external IP. The older answers that give the VM an external IP, run haproxy and open 6379 in the firewall put the cache port on a public address.

Why does redis-cli -c hang on Memorystore for Valkey from my laptop?

In cluster mode a key on another shard gets a MOVED reply naming a node's private address, such as 10.30.0.5:11002. redis-cli -c tries to connect there, and your laptop has no route to it: on our Mac it failed after 75 seconds with setsockopt(TCP_NODELAY): Invalid argument. Forward each node port as well and use a client that maps node addresses to 127.0.0.1, such as redis-py's RedisCluster with address_remap.

Ostgate runs on Apple Silicon Macs with macOS 15 or later, with a 7-day trial and no sign-up. Forward profiles are described in the tunnels and forwards docs, and internal load balancers through a bastion uses the same pattern for other private services.