Other than the suggestions already made by others, here's a checklist of things to consider when pushes don't work.
- If your total push packet exceeds 256 bytes, including the initial header, token, and JSON payload, APNS will simply drop it. If you are not using the "advanced" error detection, you will never know until your users start complaining. What you have to do is check the encoded packet size, that is, the size of the actual data you will pump down the wire, and if it's longer than 256 bytes, either reject it, or cut off some of the message text and encode it again until it is <= 256 bytes long.
- If there is anything wrong with your payload in any way, including the length, APNS will drop it, and APNS will drop your connection, too.
- If you have a persistent connection, and it is idle for about 20 minutes or so, APNS will silently drop the connection. You have to be prepared for that and reconnect.
- If your APNS certificate has expired or is incorrect, and you continue trying to connect at too high a rate, APNS will blacklist your IP address for an unknown period of time, but it's much more than a few minutes, maybe even an hour or more.
- If the iPhone does not have 3G reception, but does have WiFi, it will try to use that for push notifications. If you are in a firewalled area that does not allow outbound connections to Apple's network, your iPhone will not be able to open a socket to APNS and you are SOL.
- I am not sure if your SQL DB is updated with push tokens every time a client connects to APNS. Having a static database of push tokens is an issue, because push tokens don't stay the same forever - it even says so in the APNS programming guide. The iPhone is supposed to get the push token each time it launches, and communicate it to the server side (and I am sure you can optimize this - the iPhone could store the last token persistently and send it only if it has changed). But some things can cause the push token to change, such as re-registering the iPhone for push, and I am not sure what else. All I know is that relying on a push token to be like a GUID is asking for trouble. The next time the token changes, if your DB is not updated, goodbye push to that client.
Hope this helps.